2 Tools to mess with dicts.
6 from bisect import bisect_left, insort_left
8 from assertutil import _assert, precondition
10 def move(k, d1, d2, strict=False):
12 Move item with key k from d1 to d2.
14 if strict and not d1.has_key(k):
22 Remove all items from d1 whose key occurs in d2.
36 class DictOfSets(dict):
37 def add(self, key, value):
41 self[key] = set([value])
43 def union(self, key, values):
45 self[key].update(values)
47 self[key] = set(values)
49 def update(self, otherdictofsets):
50 for key, value in otherdictofsets.iteritems():
51 self.union(key, value)
53 def discard(self, key, value):
56 self[key].discard(value)
61 def __init__(self, initialdata={}):
63 self.update(initialdata)
65 def del_if_present(self, key):
69 def items_sorted_by_value(self):
71 @return a sequence of (key, value,) pairs sorted according to value
73 l = [(x[1], x[0],) for x in self.d.iteritems()]
75 return [(x[1], x[0],) for x in l]
77 def items_sorted_by_key(self):
79 @return a sequence of (key, value,) pairs sorted according to key
85 def __repr__(self, *args, **kwargs):
86 return self.d.__repr__(*args, **kwargs)
88 def __str__(self, *args, **kwargs):
89 return self.d.__str__(*args, **kwargs)
91 def __contains__(self, *args, **kwargs):
92 return self.d.__contains__(*args, **kwargs)
94 def __len__(self, *args, **kwargs):
95 return self.d.__len__(*args, **kwargs)
97 def __cmp__(self, other):
99 return self.d.__cmp__(other)
100 except TypeError, le:
101 # maybe we should look for a .d member in other. I know this is insanely kludgey, but the Right Way To Do It is for dict.__cmp__ to use structural typing ("duck typing")
103 return self.d.__cmp__(other.d)
107 def __eq__(self, *args, **kwargs):
108 return self.d.__eq__(*args, **kwargs)
110 def __ne__(self, *args, **kwargs):
111 return self.d.__ne__(*args, **kwargs)
113 def __gt__(self, *args, **kwargs):
114 return self.d.__gt__(*args, **kwargs)
116 def __ge__(self, *args, **kwargs):
117 return self.d.__ge__(*args, **kwargs)
119 def __le__(self, *args, **kwargs):
120 return self.d.__le__(*args, **kwargs)
122 def __lt__(self, *args, **kwargs):
123 return self.d.__lt__(*args, **kwargs)
125 def __getitem__(self, *args, **kwargs):
126 return self.d.__getitem__(*args, **kwargs)
128 def __setitem__(self, *args, **kwargs):
129 return self.d.__setitem__(*args, **kwargs)
131 def __delitem__(self, *args, **kwargs):
132 return self.d.__delitem__(*args, **kwargs)
134 def __iter__(self, *args, **kwargs):
135 return self.d.__iter__(*args, **kwargs)
137 def clear(self, *args, **kwargs):
138 return self.d.clear(*args, **kwargs)
140 def copy(self, *args, **kwargs):
141 return self.__class__(self.d.copy(*args, **kwargs))
143 def fromkeys(self, *args, **kwargs):
144 return self.__class__(self.d.fromkeys(*args, **kwargs))
146 def get(self, key, default=None):
147 return self.d.get(key, default)
149 def has_key(self, *args, **kwargs):
150 return self.d.has_key(*args, **kwargs)
152 def items(self, *args, **kwargs):
153 return self.d.items(*args, **kwargs)
155 def iteritems(self, *args, **kwargs):
156 return self.d.iteritems(*args, **kwargs)
158 def iterkeys(self, *args, **kwargs):
159 return self.d.iterkeys(*args, **kwargs)
161 def itervalues(self, *args, **kwargs):
162 return self.d.itervalues(*args, **kwargs)
164 def keys(self, *args, **kwargs):
165 return self.d.keys(*args, **kwargs)
167 def pop(self, *args, **kwargs):
168 return self.d.pop(*args, **kwargs)
170 def popitem(self, *args, **kwargs):
171 return self.d.popitem(*args, **kwargs)
173 def setdefault(self, *args, **kwargs):
174 return self.d.setdefault(*args, **kwargs)
176 def update(self, *args, **kwargs):
177 self.d.update(*args, **kwargs)
179 def values(self, *args, **kwargs):
180 return self.d.values(*args, **kwargs)
183 def __init__(self, initialdict={}):
184 self.d = copy.deepcopy(initialdict)
186 def add_num(self, key, val, default=0):
188 If the key doesn't appear in self then it is created with value default
191 self.d[key] = self.d.get(key, default) + val
193 def subtract_num(self, key, val, default=0):
194 self.d[key] = self.d.get(key, default) - val
198 @return: the sum of all values
200 return reduce(operator.__add__, self.d.values())
202 def inc(self, key, default=0):
204 Increment the value associated with key in dict. If there is no such
205 key, then one will be created with initial value 0 (before inc() --
206 therefore value 1 after inc).
208 self.add_num(key, 1, default)
210 def dec(self, key, default=0):
212 Decrement the value associated with key in dict. If there is no such
213 key, then one will be created with initial value 0 (before dec() --
214 therefore value -1 after dec).
216 self.subtract_num(key, 1, default)
218 def items_sorted_by_value(self):
220 @return a sequence of (key, value,) pairs sorted according to value
222 l = [(x[1], x[0],) for x in self.d.iteritems()]
224 return [(x[1], x[0],) for x in l]
226 def item_with_largest_value(self):
227 it = self.d.iteritems()
228 (winner, winnerval,) = it.next()
235 except StopIteration:
237 return (winner, winnerval,)
239 def items_sorted_by_key(self):
241 @return a sequence of (key, value,) pairs sorted according to key
247 def __repr__(self, *args, **kwargs):
248 return self.d.__repr__(*args, **kwargs)
250 def __str__(self, *args, **kwargs):
251 return self.d.__str__(*args, **kwargs)
253 def __contains__(self, *args, **kwargs):
254 return self.d.__contains__(*args, **kwargs)
256 def __len__(self, *args, **kwargs):
257 return self.d.__len__(*args, **kwargs)
259 def __cmp__(self, other):
261 return self.d.__cmp__(other)
262 except TypeError, le:
263 # maybe we should look for a .d member in other. I know this is insanely kludgey, but the Right Way To Do It is for dict.__cmp__ to use structural typing ("duck typing")
265 return self.d.__cmp__(other.d)
269 def __eq__(self, *args, **kwargs):
270 return self.d.__eq__(*args, **kwargs)
272 def __ne__(self, *args, **kwargs):
273 return self.d.__ne__(*args, **kwargs)
275 def __gt__(self, *args, **kwargs):
276 return self.d.__gt__(*args, **kwargs)
278 def __ge__(self, *args, **kwargs):
279 return self.d.__ge__(*args, **kwargs)
281 def __le__(self, *args, **kwargs):
282 return self.d.__le__(*args, **kwargs)
284 def __lt__(self, *args, **kwargs):
285 return self.d.__lt__(*args, **kwargs)
287 def __getitem__(self, *args, **kwargs):
288 return self.d.__getitem__(*args, **kwargs)
290 def __setitem__(self, *args, **kwargs):
291 return self.d.__setitem__(*args, **kwargs)
293 def __delitem__(self, *args, **kwargs):
294 return self.d.__delitem__(*args, **kwargs)
296 def __iter__(self, *args, **kwargs):
297 return self.d.__iter__(*args, **kwargs)
299 def clear(self, *args, **kwargs):
300 return self.d.clear(*args, **kwargs)
302 def copy(self, *args, **kwargs):
303 return self.__class__(self.d.copy(*args, **kwargs))
305 def fromkeys(self, *args, **kwargs):
306 return self.__class__(self.d.fromkeys(*args, **kwargs))
308 def get(self, key, default=0):
309 return self.d.get(key, default)
311 def has_key(self, *args, **kwargs):
312 return self.d.has_key(*args, **kwargs)
314 def items(self, *args, **kwargs):
315 return self.d.items(*args, **kwargs)
317 def iteritems(self, *args, **kwargs):
318 return self.d.iteritems(*args, **kwargs)
320 def iterkeys(self, *args, **kwargs):
321 return self.d.iterkeys(*args, **kwargs)
323 def itervalues(self, *args, **kwargs):
324 return self.d.itervalues(*args, **kwargs)
326 def keys(self, *args, **kwargs):
327 return self.d.keys(*args, **kwargs)
329 def pop(self, *args, **kwargs):
330 return self.d.pop(*args, **kwargs)
332 def popitem(self, *args, **kwargs):
333 return self.d.popitem(*args, **kwargs)
335 def setdefault(self, *args, **kwargs):
336 return self.d.setdefault(*args, **kwargs)
338 def update(self, *args, **kwargs):
339 return self.d.update(*args, **kwargs)
341 def values(self, *args, **kwargs):
342 return self.d.values(*args, **kwargs)
344 def del_if_present(d, k):
348 class ValueOrderedDict:
350 Note: this implementation assumes that the values do not mutate and change
351 their sort order. That is, it stores the values in a sorted list and
352 as items are added and removed from the dict, it makes updates to the list
353 which will keep the list sorted. But if a value that is currently sitting
354 in the list changes its sort order, then the internal consistency of this
357 If that happens, and if assertion checking is turned on, then you will get
358 an assertion failure the very next time you try to do anything with this
359 ValueOrderedDict. However, those internal consistency checks are very slow
360 and almost certainly unacceptable to leave turned on in production code.
363 def __init__(self, c):
369 precondition(self.i <= len(self.c.l), "The iterated ValueOrderedDict doesn't have this many elements. Most likely this is because someone altered the contents of the ValueOrderedDict while the iteration was in progress.", self.i, self.c)
370 precondition((self.i == len(self.c.l)) or self.c.d.has_key(self.c.l[self.i][1]), "The iterated ValueOrderedDict doesn't have this key. Most likely this is because someone altered the contents of the ValueOrderedDict while the iteration was in progress.", self.i, (self.i < len(self.c.l)) and self.c.l[self.i], self.c)
371 if self.i == len(self.c.l):
373 le = self.c.l[self.i]
375 return (le[1], le[0],)
378 return ValueOrderedDict.ItemIterator(self)
381 return zip(map(operator.__getitem__, self.l, [1]*len(self.l)), map(operator.__getitem__, self.l, [0]*len(self.l)))
384 return map(operator.__getitem__, self.l, [0]*len(self.l))
387 return map(operator.__getitem__, self.l, [1]*len(self.l))
390 def __init__(self, c):
396 precondition(self.i <= len(self.c.l), "The iterated ValueOrderedDict doesn't have this many elements. Most likely this is because someone altered the contents of the ValueOrderedDict while the iteration was in progress.", self.i, self.c)
397 precondition((self.i == len(self.c.l)) or self.c.d.has_key(self.c.l[self.i][1]), "The iterated ValueOrderedDict doesn't have this key. Most likely this is because someone altered the contents of the ValueOrderedDict while the iteration was in progress.", self.i, (self.i < len(self.c.l)) and self.c.l[self.i], self.c)
398 if self.i == len(self.c.l):
400 le = self.c.l[self.i]
405 return ValueOrderedDict.KeyIterator(self)
408 def __init__(self, c):
414 precondition(self.i <= len(self.c.l), "The iterated ValueOrderedDict doesn't have this many elements. Most likely this is because someone altered the contents of the ValueOrderedDict while the iteration was in progress.", self.i, self.c)
415 precondition((self.i == len(self.c.l)) or self.c.d.has_key(self.c.l[self.i][1]), "The iterated ValueOrderedDict doesn't have this key. Most likely this is because someone altered the contents of the ValueOrderedDict while the iteration was in progress.", self.i, (self.i < len(self.c.l)) and self.c.l[self.i], self.c)
416 if self.i == len(self.c.l):
418 le = self.c.l[self.i]
422 def itervalues(self):
423 return ValueOrderedDict.ValueIterator(self)
425 def __init__(self, initialdata={}):
426 self.d = {} # k: key, v: val
427 self.l = [] # sorted list of tuples of (val, key,)
428 self.update(initialdata)
429 assert self._assert_invariants()
434 def __repr_n__(self, n=None):
437 iter = self.iteritems()
439 s.append(str(x[0])); s.append(": "); s.append(str(x[1]))
441 while (n is None) or (i < n):
443 s.append(", "); s.append(str(x[0])); s.append(": "); s.append(str(x[1]))
444 except StopIteration:
450 return "<%s %s>" % (self.__class__.__name__, self.__repr_n__(),)
453 return "<%s %s>" % (self.__class__.__name__, self.__repr_n__(16),)
455 def __eq__(self, other):
456 for (k, v,) in other.iteritems():
457 if not self.d.has_key(k) or self.d[k] != v:
461 def __ne__(self, other):
462 return not self.__eq__(other)
464 def _assert_invariants(self):
465 iter = self.l.__iter__()
470 # self.l is required to be sorted
471 _assert(x >= oldx, x, oldx)
472 # every element of self.l is required to appear in self.d
473 _assert(self.d.has_key(x[1]), x)
475 except StopIteration:
477 for (k, v,) in self.d.iteritems():
478 i = bisect_left(self.l, (v, k,))
479 while (self.l[i][0] is not v) or (self.l[i][1] is not k):
481 _assert(i < len(self.l), i, len(self.l), k, v, self.l)
482 _assert(self.l[i][0] is v, i, v, l=self.l, d=self.d)
483 _assert(self.l[i][1] is k, i, k, l=self.l, d=self.d)
486 def insert(self, key, val=None):
487 assert self._assert_invariants()
488 result = self.__setitem__(key, val)
489 assert self._assert_invariants()
492 def setdefault(self, key, default=None):
493 assert self._assert_invariants()
494 if not self.has_key(key):
496 assert self._assert_invariants()
499 def __setitem__(self, key, val=None):
500 assert self._assert_invariants()
501 if self.d.has_key(key):
505 i = bisect_left(self.l, (oldval, key,))
506 while (self.l[i][0] is not oldval) or (self.l[i][1] is not key):
509 insort_left(self.l, (val, key,))
510 elif oldval is not val:
512 i = bisect_left(self.l, (oldval, key,))
513 while (self.l[i][0] is not oldval) or (self.l[i][1] is not key):
515 self.l[i] = (val, key,)
517 insort_left(self.l, (val, key,))
520 assert self._assert_invariants()
523 def remove(self, key, default=None, strictkey=True):
524 assert self._assert_invariants()
525 result = self.__delitem__(key, default, strictkey)
526 assert self._assert_invariants()
529 def __getitem__(self, key, default=None, strictkey=True):
530 if not self.d.has_key(key):
537 def __delitem__(self, key, default=None, strictkey=True):
539 @param strictkey: True if you want a KeyError in the case that
540 key is not there, False if you want a reference to default
541 in the case that key is not there
542 @param default: the object to return if key is not there; This
543 is ignored if strictkey.
545 @return: the object removed or default if there is not item by
546 that key and strictkey is False
548 assert self._assert_invariants()
549 if self.d.has_key(key):
550 val = self.d.pop(key)
551 i = bisect_left(self.l, (val, key,))
552 while (self.l[i][0] is not val) or (self.l[i][1] is not key):
555 assert self._assert_invariants()
558 assert self._assert_invariants()
561 assert self._assert_invariants()
565 assert self._assert_invariants()
568 assert self._assert_invariants()
570 def update(self, otherdict):
574 assert self._assert_invariants()
575 for (k, v,) in otherdict.iteritems():
577 assert self._assert_invariants()
580 def has_key(self, key):
581 assert self._assert_invariants()
582 return self.d.has_key(key)
586 raise KeyError, 'popitem(): dictionary is empty'
589 return (le[1], le[0],)
591 def pop(self, k, default=None, strictkey=False):
592 if not self.d.has_key(k):
598 i = bisect_left(self.l, (v, k,))
599 while (self.l[i][0] is not v) or (self.l[i][1] is not k):
604 def pop_from_list(self, i=0):
609 class AuxValueDict(dict):
610 """I behave like a regular dict, but each key is associated with two
611 values: the main value, and an auxilliary one. Setting the main value
612 (with the usual d[key]=value) clears the auxvalue. You can set both main
613 and auxvalue at the same time, and can retrieve the values separately.
615 The main use case is a dictionary that represents unpacked child values
616 for a directory node, where a common pattern is to modify one or more
617 children and then pass the dict back to a packing function. The original
618 packed representation can be cached in the auxvalue, and the packing
619 function can use it directly on all unmodified children. On large
620 directories with a complex packing function, this can save considerable
623 def __init__(self, *args, **kwargs):
624 super(AuxValueDict, self).__init__(*args, **kwargs)
627 def __setitem__(self, key, value):
628 super(AuxValueDict, self).__setitem__(key, value)
629 self.auxilliary[key] = None # clear the auxvalue
631 def __delitem__(self, key):
632 super(AuxValueDict, self).__delitem__(key)
633 self.auxilliary.pop(key)
635 def get_aux(self, key, default=None):
636 """Retrieve the auxilliary value. There is no way to distinguish
637 between an auxvalue of 'None' and a key that does not have an
638 auxvalue, and get_aux() will not raise KeyError when called with a
640 return self.auxilliary.get(key, default)
642 def set_with_aux(self, key, value, auxilliary):
643 """Set both the main value and the auxilliary value. There is no way
644 to distinguish between an auxvalue of 'None' and a key that does not
646 super(AuxValueDict, self).__setitem__(key, value)
647 self.auxilliary[key] = auxilliary