#!/usr/bin/env python
""" Convenience methods for list comparison & manipulation
Fast and useful, set/frozenset* only retain unique values,
duplicates are automatically removed.
lr_union union
merge values, remove duplicates
lr_diff difference
left elements, subtracting any in common with right
lr_intr intersection
only common values found in both left and right
lr_symm symmetric_difference
omit values found in both left and right
lr_cont issuperset
test left contains all values from right
* Unlike set, frozenset preserves its own order and is
immutable. They do not preserve the source-order.
"""
lr_union = lambda l, r: list(set(l).union(r))
lr_diff = lambda l, r: list(set(l).difference(r))
lr_intr = lambda l, r: list(set(l).intersection(r))
lr_symm = lambda l, r: list(set(l).symmetric_difference(r))
lr_cont = lambda l, r: set(l).issuperset(r)
# silent example of lr_intr if None is passed instead of list
lrq_intr = lambda l, r: list(set(l).intersection(r or []))
# ------------ NOTHING BELOW HERE IS REQUIRED --------------
def tests():
""" doctest tests/examples for set and set conveniences
A few examples without the conveniences above.
Strings are a form of list, they can be passed where apropriate
>>> set('aabbcc') # only unique are returned
set(['a', 'c', 'b'])
Do the work and cast as list (switch to tuple if prefered)
>>> list(set('aabbcc'))
['a', 'c', 'b']
Using list does not remove duplicates
>>> list('aabbcc') # list is not unique
['a', 'a', 'b', 'b', 'c', 'c']
Simple join of lists, note the redundant values
>>> ['a', 'a', 'b'] + ['b', 'c', 'c']
['a', 'a', 'b', 'b', 'c', 'c']
Join both lists, return only unique values, join list before set (slower)
>>> list(set(['a', 'a', 'b'] + ['b', 'c', 'c']))
['a', 'c', 'b']
Join lists, as above, using built-in set library (faster)
>>> lr_union(['a', 'a', 'b'], ['b', 'c', 'c'])
['a', 'c', 'b']
Remove right values from left
>>> lr_diff(['a', 'b'], ['b', 'c'])
['a']
Remove as above, swapped/reordered inputs to remove left from right
>>> lr_diff(['b', 'c'], ['a', 'b'])
['c']
Common elements
>>> lr_intr(['a', 'b'], ['b', 'c'])
['b']
Unique elements (remove the common, intersecting, values)
Note: similar to left-right + right-left.
>>> lr_symm(['a', 'b'], ['b', 'c'])
['a', 'c']
Is left a superset of (does it contain) the right
>>> lr_cont(['a', 'b'], ['b', 'c'])
False
>>> lr_cont(['a', 'b', 'c'], ['b', 'c'])
True
Marginally less trite examples using words
>>> lwords = 'the quick brown fox'.split()
>>> rtags = 'brown,fox,jumps,over'.split(',')
Return all unique words from both lists.
>>> lr_union(lwords,rtags)
['brown', 'over', 'fox', 'quick', 'the', 'jumps']
Return unique common, intersecting, words. Members of left AND right only.
>>> lr_intr(lwords,rtags)
['brown', 'fox']
Return unique uncommon words. Members of left OR right
>>> lr_symm(lwords,rtags)
['quick', 'the', 'jumps', 'over']
Note: intersection + symmetric = union, but don't count on their order!
"""
def insecure_demo():
"""Compact method to demo functionality"""
left, right = list('aab'), list('bcc')
both = left + right
both.sort()
lamb_dict = {'Difference (Remainder of subtract: left - right)': 'lr_diff',
'Intersection (Only in left AND right)': 'lr_intr',
'Symmetric Difference (Only in left OR right)': 'lr_symm',
'Union (Unique list of ALL values)': 'lr_union'}
print "Demo methods for comparing lists using set/frozenset\n"
print "'left' list: %s" % repr(left)
print "'right' list: %s" % repr(right)
print "'both' lists: %s\n" % repr(both)
print '-' * 30
for lamb_desc, lamb_name in lamb_dict.items():
lamb_func = globals().get(lamb_name)
resp = lamb_func(left, right)
resp.sort()
print lamb_desc #'Obtain the %s of two lists' % lamb_name.split('_')[-1]
print '>>> %s(%r, %r)' % (lamb_name, left, right)
print resp
print '-' * 30
if __name__ == '__main__':
import doctest
doctest.testmod()
insecure_demo()
URL = 'http://docs.python.org/2/library/stdtypes.html#set-types-set-frozenset'
print "\nBe sure to visit:\n", URL