Source code for calcpy._set

from copy import copy
import functools

from .matcher import _get_matcher
from .typing import DictTypes
from ._it import pairwise
from ._seq import _unique_sequence
from ._op import _concat, concat


[docs] def union(*args, key=None): """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'] See also: https://docs.python.org/3/library/stdtypes.html#frozenset.union """ matcher = _get_matcher(args[0], key=key) concated = _concat(*args, matcher=matcher, assemble=False) return _unique_sequence(concated, matcher=matcher, dissemble=False)
[docs] def isdisjoint(*args, key=None): """Check if the parameters are disjoint. Parameters: *args key (callable) Returns: bool: Examples: >>> isdisjoint([1, 2, 3], [2, 3, 4], [3, 4]) False >>> isdisjoint([1, 2, 3], [4, 5, 6], [7, 8, 9]) True See also: https://docs.python.org/3/library/stdtypes.html#frozenset.isdisjoint """ concated = concat(*args, key=key) unioned = union(*args, key=key) return len(concated) == len(unioned)
def _wrapper2(fun, matcher): def f(loper, roper): loper = matcher.disassemble(loper) roper = matcher.disassemble(roper) results = fun(loper, roper, matcher) return matcher.assemble(results) return f def _wrapper(fun): """Extend binary function to multi-ary function.""" def f(*args, key=None): if len(args) == 0: return args matcher = _get_matcher(args[0], key=key) return functools.reduce(_wrapper2(fun, matcher=matcher), args) return f def _wrapper_1dict(fun): """Support the case when the first parameter is a dict.""" def f(*args, key=None): op = _wrapper(fun) if len(args) >= 1 and isinstance(args[0], DictTypes): arg = args[0] arglist = list(arg) params = list(args) params[0] = arglist keys = op(*params, key=key) results = copy(arg) for key in arglist: if key not in keys: results.pop(key) return results return op(*args, key=key) return f def _contains(seq, obj, matcher): for element in seq: if matcher.eq(obj, element): return True else: return False def _intersection2(loper, roper, key=None, matcher=None): matcher = _get_matcher(loper, key=key, matcher=matcher) results = [] for l in loper: # noqa: E741 if _contains(roper, l, matcher=matcher): results.append(l) return results def _difference2(loper, roper, key=None, matcher=None): matcher = _get_matcher(loper, key=key, matcher=matcher) results = [] for l in loper: # noqa: E741 if not _contains(roper, l, matcher=matcher): results.append(l) return results def _symmetric_difference2(loper, roper, matcher): return concat(_difference2(loper, roper, matcher=matcher), _difference2(roper, loper, matcher=matcher)) def _issubset2(loper, roper, matcher): for l in loper: # noqa: E741 if not _contains(roper, l, matcher=matcher): return False return True def _issuperset2(loper, roper, matcher): for r in roper: if not _contains(loper, r, matcher=matcher): return False return True def _ispropersubset2(loper, roper, matcher): return _issubset2(loper, roper, matcher) and not _issuperset2(loper, roper, matcher) def _ispropersuperset2(loper, roper, matcher): return _issuperset2(loper, roper, matcher) and not _issubset2(loper, roper, matcher)
[docs] def contains(values, /, *args, key=None): """Check if the first parameter contains the follow-up parameters. Parameters: values (str | bytes | bytearray | (list | tuple | pd.Series)[str]): *args key (callable, optional) Returns: 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 """ matcher = _get_matcher(values, key=key) for arg in args: if not _contains(values, arg, matcher=matcher): return False return True
intersection = _wrapper_1dict(_intersection2) intersection.__doc__ = \ """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} See also: https://docs.python.org/3/library/stdtypes.html#frozenset.intersection """ difference = _wrapper_1dict(_difference2) difference.__doc__ = \ """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} See also: https://docs.python.org/3/library/stdtypes.html#frozenset.difference """ symmetric_difference = _wrapper(_symmetric_difference2) symmetric_difference.__doc__ = \ """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' See also: https://docs.python.org/3/library/stdtypes.html#frozenset.symmetric_difference """ def _allpairwise_wrapper(fun): """Wrapper for better function signatures.""" def f(*args, key=None): if len(args) <= 1: return True matcher = _get_matcher(args[0], key=key) return all(fun(*p, matcher=matcher) for p in pairwise(args)) return f issubset = _allpairwise_wrapper(_issubset2) issubset.__doc__ = \ """Check if the parameter is a subset of the follow-up parameter. Parameters: *args key (callable) Returns: 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 See also: https://docs.python.org/3/library/stdtypes.html#frozenset.issubset """ issuperset = _allpairwise_wrapper(_issuperset2) issuperset.__doc__ = \ """Check if the parameter is a superset of the follow-up parameter. Parameters: *args key (callable) Returns: 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 See also: https://docs.python.org/3/library/stdtypes.html#frozenset.issuperset """ ispropersubset = _allpairwise_wrapper(_ispropersubset2) ispropersubset.__doc__ = \ """Check if the parameter is a proper subset of the follow-up parameter. Parameters: *args key (callable) Returns: 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 """ ispropersuperset = _allpairwise_wrapper(_ispropersuperset2) ispropersuperset.__doc__ = \ """Check if the parameter is a proper superset of the follow-up parameter. Parameters: *args key (callable) Returns: 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 """