Skip to content

Instantly share code, notes, and snippets.

@kylebgorman
Created November 2, 2013 06:01
Show Gist options
  • Save kylebgorman/7276048 to your computer and use it in GitHub Desktop.
Save kylebgorman/7276048 to your computer and use it in GitHub Desktop.
a Python dictionary with all the set operators
#!/usr/bin/env python -O
#
# Copyright (c) 2013 Kyle Gorman
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# dictpp.py: adding set operations (and semantics) to dictionaries
# Kyle Gorman <gormanky@ohsu.edu>
class DictPP(dict):
"""
A Python dictionary, now with set operations. These operate on keys,
rather than on key-value pairs (as you might expect) as there is no
reason to assume that a value will be immutable/hashable.
"""
def isdisjoint(self, other):
"""
True iff self and other share no keys
>>> x = DictPP({'spam': 5, 'eggs': 3})
>>> y = DictPP({'liver': 2})
>>> z = DictPP({'spam': 2})
>>> x.isdisjoint(y)
True
>>> x.isdisjoint(z)
False
"""
return set(self).isdisjoint(other)
# no need to implement issubset (<=) or issuperset (>=); base
# dictionaries already have those methods
def __sub__(self, other):
"""
Difference: items in self whose keys are not in other
>>> x = DictPP({'spam': 5, 'eggs': 3})
>>> y = DictPP({'liver': 2})
>>> z = DictPP({'spam': 2})
>>> (x - y) == x
True
>>> sorted((x - z).keys())
['eggs']
>>> sorted((x - x).keys())
[]
"""
return {k: v for (k, v) in self.iteritems() if k not in other}
def difference(self, other):
return self - other
def __isub__(self, other):
return self - other
def difference_update(self, other):
self -= other
def __xor__(self, other):
"""
Symmetric difference: items in self whose keys are not in other,
or items in other whose keys are not in self
>>> x = DictPP({'spam': 5, 'eggs': 3})
>>> y = DictPP({'liver': 2})
>>> z = DictPP({'spam': 2})
>>> sorted((x ^ y).keys())
['eggs', 'liver', 'spam']
>>> sorted((x ^ z).keys())
['eggs']
"""
return DictPP(self - other) | DictPP(other - self)
def symmetric_difference(self, other):
return self ^ other
def __ixor__(self, other):
return self ^ other
def symmetric_difference_update(self, other):
self ^= other
def __and__(self, other):
"""
Intersection: items in self whose keys are also in other
>>> x = DictPP({'spam': 5, 'eggs': 3})
>>> y = DictPP({'liver': 2})
>>> z = DictPP({'spam': 2})
>>> sorted((x & y).keys())
[]
>>> sorted((x & z).keys())
['spam']
"""
return {k: v for (k, v) in self.iteritems() if k in other}
def intersection(self, other):
return self & other
def __iand__(self, other):
return self & other
def intersection_update(self, other):
self &= other
def __or__(self, other):
"""
Union: items in self and items in other
>>> x = DictPP({'spam': 5, 'eggs': 3})
>>> y = DictPP({'liver': 2})
>>> z = DictPP({'spam': 2})
>>> sorted((x | y).keys())
['eggs', 'liver', 'spam']
>>> sorted((x | z).keys())
['eggs', 'spam']
"""
return dict(self, **other)
def union(self, other):
return self | other
def __ior__(self, other):
return self | other
# note that update does not need to be implemented; it already exists
# in normal dictionaries
if __name__ == '__main__':
import doctest
doctest.testmod()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment