"""Simplified Set functions for any iterable arguments. Runs fast. Easy to understand. Works nicely with all iterables. Does not support sets of sets. Uses dictionaries rather than a custom datatype. Set functions that work on any iterable: - set (constructs a dictionary) - issubset, issuperset, isset, equals - union, intersection, difference, symmetric_difference Set functions available after using the set() constructor to make a dictionary: - Uniquifying a sequence list(set(iterable)) - Membership testing if elem in set(iterable) - Iteration for elem in set(iterable) - Cardinality len(set(iterable)) """ __all__ = ['set', 'isset', 'issubset', 'issuperset', 'equals', 'union', 'intersection', 'difference', 'symmetric_difference'] def set(iterable, value=True): """Creates a new set (dictionary) from an iterable. The dictionary form is useful for set membership testing and iteration. """ result = {} for elem in iterable: result[elem] = value return result def _set(iterable): """Coerce to a dictionary unless it is already a dictionary.""" if isinstance(iterable, dict): return iterable return set(iterable) def isset(iterable, value=True): """Returns true if the iterable has no duplicate elements.""" if isinstance(iterable, dict): return True uniq = {} for elem in iterable: if elem in uniq: return False uniq[elem] = value return True def issubset(s1, s2): """Return true if s1 is a subset of s2.""" s2 = _set(s2) for elem in s1: if elem not in s2: return False return True def issuperset(s1, s2): """Return true if s1 is a superset of s2.""" return issubset(s2, s1) def equals(s1, s2): """Return true if s1 and s2 each have the same elements.""" s1, s2 = _set(s1), _set(s2) return len(s1) == len(s2) and issubset(s1,s2) def union(s1, s2): """Return new set (dict) with elements from both s1 and s2.""" result = set(s1) result.update(_set(s2)) return result def intersection(s1, s2): """Return new set (dict) with elements common to s1 and s2.""" small, big = s1, s2 if len(small) > len(big): small, big = big, small big = _set(big) return set(filter(big.has_key, small)) def difference(s1, s2, value=True): """Return the difference of two sets as a new set (dict).""" s2 = _set(s2) result = {} for elem in s1: if elem not in s2: result[elem] = value return result def symmetric_difference(s1, s2, value=True): """Return new set (dict) with elements in s1 and s2 but not in both.""" s1 = _set(s1) s2 = _set(s2) result = {} for elem in s1: if elem not in s2: result[elem] = value for elem in s2: if elem not in s1: result[elem] = value return result if __name__ == '__main__': print 'IsSet', isset('factoid'), isset('misinformation') print 'Equals', equals('algorithm','logarithm'), equals('sin','cos') print 'Subset', issubset('heart', 'thread'), issubset('treat','tryst') a = 'abracadabra' b = 'alacazam' print 'Union', list(union(a,b)) print 'Intersection', list(intersection(a,b)) print 'Difference', list(difference(a,b)) print 'SymmetricDifference', list(symmetric_difference(a,b)) print 'Uniquification', list(set(a)) print 'Length', len(set(a)) print 'Iteration', [letter.upper() for letter in set(a)] print 'Membership', 'b' in set(a), 'e' in set(a)