Python: How To Get A Subset Of Dict
Solution 1:
Edit: A dictionary is not ordered. It is impossible to make get_range
return the same slice whenever you have modified the dictionary. If you need deterministic result, replace your dict
with a collections.OrderedDict
.
Anyway, you could get a slice using itertools.islice
:
import itertools
defget_range(dictionary, begin, end):
return dict(itertools.islice(dictionary.iteritems(), begin, end+1))
The previous answer that filters by key is kept below:
With @Douglas' algorithm, we could simplify it by using a generator expression:
defget_range(dictionary, begin, end):
return dict((k, v) for k, v in dictionary.iteritems() ifbegin <= k <= end)
BTW, don't use dict
as the variable name, as you can see here dict
is a constructor of dictionary.
If you are using Python 3.x, you could use dictionary comprehension directly.
defget_range(dictionary, begin, end):
return {k: v for k, v in dictionary.items() ifbegin <= k <= end}
Solution 2:
Straight forward implementation:
defget_range(d, begin, end):
result = {}
for (key,value) in d.iteritems():
if key >= beginand key <= end:
result[key] = value
return result
One line:
defget_range2(d, begin, end):
return dict([ (k,v) for (k,v) in d.iteritems() if k >= beginand k <= end ])
Solution 3:
resting assured that what you really want an OrderedDict
, you can also use enumerate
:
#!/usr/bin/env pythondefget_range(d, begin, end):
return dict(e for i, e in enumerate(d.items()) ifbegin <= i <= end)
if __name__ == '__main__':
print get_range({"a":"b", "c":"d", "e":"f"}, 0, 1)
output:
{'a': 'b', 'c': 'd'}
ps: I let you use 0, 1
as range values, but you should use 0, 2
to sign the "first two elements" (and use begin <= i < end
as comparison function
Solution 4:
As others have mentioned, in Python dictionaries are inherently unordered. However at any given moment a list of their current keys or key,value pairs can be obtained by using their keys()
or items()
methods.
A potential problem with using these lists is that not only their contents, but also the order it is returned in will likely vary if the dictionary has been modified (or mutated) since the last time they were used. This means you generally can't store and reuse the list unless you update it every time the dictionary is is changed just in case you're going to need it.
To make this approach more manageable you can combining a dictionary and the auxiliary list into a new derived class which takes care of the synchronization between the two and also provides a get_range()
method that make use of the list's current contents. Below is sample code showing how this could be done. It's based on ideas I got from the code in this ActiveState Python Recipe.
classdict_with_get_range(dict):
def__init__(self, *args, **kwrds):
dict.__init__(self, *args, **kwrds)
self._list_ok = Falsedef_rebuild_list(self):
self._list = []
for k,v in self.iteritems():
self._list.append((k,v))
self._list_ok = Truedefget_range(self, begin, end):
ifnot self._list_ok:
self._rebuild_list()
returndict(self._list[i] for i inrange(begin,end+1))
def_wrapMutatorMethod(methodname):
_method = getattr(dict, methodname)
defwrapper(self, *args, **kwrds):
# Reset 'list OK' flag, then delegate to the real mutator method
self._list_ok = Falsereturn _method(self, *args, **kwrds)
setattr(dict_with_get_range, methodname, wrapper)
for methodname in'delitem setitem'.split():
_wrapMutatorMethod('__%s__' % methodname)
for methodname in'clear update setdefault pop popitem'.split():
_wrapMutatorMethod(methodname)
del _wrapMutatorMethod # no longer needed
dct = dict_with_get_range({"a":"b", "c":"d", "e":"f"})
print dct.get_range(0, 1)
# {'a': 'b', 'c': 'd'}del dct["c"]
print dct.get_range(0, 1)
# {'a': 'b', 'e': 'f'}
The basic idea is to derive a new class from dict
that also has an internal contents list for use by the new get_range()
method it provides that regular dictionary objects don't. To minmize the need to update (or even create) this internal list, it also has a flag indicating whether or not the list is up-to-date, and only checks it and rebuilds the list when necessary.
To maintain the flag, each inherited dictionary method which potentially changes (or mutates) the dictionary's contents is "wrapped" with helper function the resets the flag and then chains to the normal dictionary method to actually perform the operation. Installing them into the class is simply a matter of putting the names of the methods in one of two lists and then passing them one at time to an auxiliary utility immediately following the creation of the class.
Post a Comment for "Python: How To Get A Subset Of Dict"