Set Operations

calcpy provides a set of set operations that extend the built-in Python set operations, including union, intersection, difference, symmetric_difference, issubset, issuperset, and isdisjoint.

The extended APIs have the following features:

  • Preserve order: Unlike Python’s built-in set operations which don’t guarantee order, calcpy preserves the original order of elements.

  • Support object types: Works with list, tuple, set, str, np.ndarray, pd.Series, pd.DataFrame, and more.

  • Support multiple arguments: Most operations can take any number of arguments.

  • Support customizable comparison: You can provide customed comparison functions via the keyword parameter key.

Example Usages

Merge three lists:

>>> from calcpy import union
>>> union([1, 3, 5, 7], [2, 3, 4], [7, 8, 9])
[1, 3, 5, 7, 2, 4, 8, 9]

Intersection of tuples:

>>> from calcpy import intersection
>>> intersection((1, 3, 5, 7), (3, 4, 5), (5, 7, 9))
(5,)

Symmetric difference among strings:

>>> from calcpy import symmetric_difference
>>> symmetric_difference("abc", "bcd", "cde")
'ace'

Working with Dictionaries

The set operations of calcpy have special behavior when working with dictionaries:

Union with Dictionaries: When using union() with dictionaries, it merges them while preserving keys from the first dictionary in case of conflicts:

>>> from calcpy import union
>>> union({"a": 1, "b": 2}, {"b": 3, "c": 4})
{"a": 1, "b": 2, "c": 4}

This differs from Python’s dictionary union operator (|), which would use the value from the second dictionary for conflicting keys.

Intersection and Difference with Dictionaries: When using intersection() and difference() with dictionaries, the operations are performed on the dictionary keys. For example: When the first argument is a dict and subsequent arguments are list s, intersection() and difference() operate on the dictionary keys:

>>> from calcpy import intersection, difference
>>> intersection({"a": 1, "b": 2, "c": 3}, ["a", "b", "d"])
{"a": 1, "b": 2}
>>> difference({"a": 1, "b": 2, "c": 3}, ["a"], ["d"])
{"b": 2, "c": 3}

Set Operation APIs

calcpy.contains(values, /, *args, key=None)[source]

Check if the first parameter contains the follow-up parameters.

Parameters:
  • values (str | bytes | bytearray | (list | tuple | pd.Series)[str])

  • *args

  • key (callable, optional)

Return type:

bool

Examples

>>> contains([1, 2])   # return True when no elements to check
True
>>> contains([1, 2], 1)
True
>>> contains([1, 2], 3)
False
>>> contains([1, 2], 1, 2)
True
>>> contains([1, 2], 1, 2, 2)
True
>>> contains({'a': 1, 'b': 2}, 'a', 'b')
True
>>> contains({'a': 1, 'b': 2}, 'a', 'c')
False
calcpy.difference(*args, key=None)

Exclude follow-up parameters from the first one.

The first argument can be a dict, while the following positions can not be a dict. If the first argument is a dict, it means to exclude all elements in the follow-up arguments out of the key of the first position argument.

Parameters:
  • *args

  • key (callable)

Examples

>>> difference('abcd', 'cat', 'bed')
''

The case when the first argument is a dict.

>>> difference({'a': 1, 'b': 2, 'c': 3})
{'a': 1, 'b': 2, 'c': 3}
>>> difference({'a': 1, 'b': 2, 'c': 3}, ['b'])
{'a': 1, 'c': 3}
calcpy.intersection(*args, key=None)

Intersect of multiple parameters.

The first argument can be a dict, while the following positions can not be a dict. If the first argument is a dict, it means to limit the keys of the first arugment within the list specified by the intersection of follow-up position arguments (if any).

Parameters:
  • *args

  • key (callable)

Examples

>>> intersection('abcd', 'edc')
'cd'

The case when the first argument is a dict.

>>> intersection({'a': 1, 'b': 2, 'c': 3})
{'a': 1, 'b': 2, 'c': 3}
>>> intersection({'a': 1, 'b': 2, 'c': 3}, ['a', 'c'])
{'a': 1, 'c': 3}
calcpy.isdisjoint(*args, key=None)[source]

Check if the parameters are disjoint.

Parameters:
  • *args

  • key (callable)

Return type:

bool

Examples

>>> isdisjoint([1, 2, 3], [2, 3, 4], [3, 4])
False
>>> isdisjoint([1, 2, 3], [4, 5, 6], [7, 8, 9])
True
calcpy.ispropersubset(*args, key=None)

Check if the parameter is a proper subset of the follow-up parameter.

Parameters:
  • *args

  • key (callable)

Return type:

bool

Examples

>>> ispropersubset([1, 2, 3], [1, 2, 3, 4, 5])
True
>>> ispropersubset([], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5])
True
>>> ispropersubset([1, 2, 3], [1, 5, 6])
False
>>> ispropersubset([1, 2, 3], [1, 2, 3])
False
calcpy.ispropersuperset(*args, key=None)

Check if the parameter is a proper superset of the follow-up parameter.

Parameters:
  • *args

  • key (callable)

Return type:

bool

Examples

>>> ispropersuperset([1, 2, 3, 4, 5], [1, 2, 3])
True
>>> ispropersuperset([1, 2, 3, 4, 5], [1, 2, 3, 4], [1, 2, 3], [])
True
>>> ispropersuperset([1, 2, 3], [4, 5, 6])
False
>>> ispropersuperset([1, 2, 3], [1, 2, 3])
False
calcpy.issubset(*args, key=None)

Check if the parameter is a subset of the follow-up parameter.

Parameters:
  • *args

  • key (callable)

Return type:

bool

Examples

>>> issubset([1, 2, 3], [1, 2, 3, 4, 5])
True
>>> issubset([], [1, 2, 3], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5])
True
>>> issubset([1, 2, 3], [1, 5, 6])
False
calcpy.issuperset(*args, key=None)

Check if the parameter is a superset of the follow-up parameter.

Parameters:
  • *args

  • key (callable)

Return type:

bool

Examples

>>> issuperset([1, 2, 3, 4, 5], [1, 2, 3])
True
>>> issuperset([1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3], [])
True
>>> issuperset([1, 2, 3], [4, 5, 6])
False
calcpy.symmetric_difference(*args, key=None)

Pick elements that appear in odd number of parameters.

Parameters:
  • *args

  • key (callable)

Examples

>>> symmetric_difference([1, 2, 3], [2, 3, 4], [3, 4])
[1, 3]
>>> symmetric_difference('hello', 'he', 'okay')
'llkay'
calcpy.union(*args, key=None)[source]

Union of multiple parameters.

This function can merge multiple dict’s into one dict. If two dict’s d1 and d2 have the same key k, union(d1, d2) will use the value of d1[k] rather than d2[k], which differs from d1 | d2 who takes d2[k].

Parameters:
  • *args

  • key (callable)

Examples

>>> union([1, 2, 3], [3, 2], [2, 4], [])
[1, 2, 3, 4]
>>> union((1, 2, 3), (3, 2), (2, 4), ())
(1, 2, 3, 4)

The following example considers a list and moves some of its elements to the front.

>>> a = [1, 2, 3, 4, 5]  # the list
>>> f = [3, 4]  # some elements that need to appear first
>>> union(f, a)
[3, 4, 1, 2, 5]

Union of multiple dict’s:

>>> union({'a': 1, 'b': 2}, {'c': 13, 'a': 11}, {})
{'a': 1, 'b': 2, 'c': 13}

Use key:

>>> union(["alpha", "beta"], ["gamma", "delta"], ["pi", "omega"], key=len)
['alpha', 'beta', 'pi']