Python: how to get a subset of dict

I have a dict that has many elements, I want to write a function that can return elements in a given range of indices (consider dict as array):

get_range(dict, begin, end): return {a new dict for all the indexes between begin and end} 

How can I do that?

EDIT: I am not asking to use a key filter ... for example)

 {"a":"b", "c":"d", "e":"f"} get_range(dict, 0, 1) returns {"a":"b", "c":"d"} (the first 2 elements) 

I donโ€™t care, sorting ... I actually implement server side swapping ...

+7
python
source share
4 answers

Edit: Dictionary is not ordered. It is not possible to make get_range return the same fragment each time the dictionary is changed. If you need a deterministic result, replace dict with collections.OrderedDict .

Anyway, you can get the snippet using itertools.islice :

 import itertools def get_range(dictionary, begin, end): return dict(itertools.islice(dictionary.iteritems(), begin, end+1)) 

The previous answer that filters the key is stored below:

With the @ Douglas algorithm, we could simplify it with a generator expression:

 def get_range(dictionary, begin, end): return dict((k, v) for k, v in dictionary.iteritems() if begin <= k <= end) 

BTW, do not use dict as a variable name, as you can see here dict is a dictionary constructor.

If you are using Python 3.x, you can directly use dictionary understanding.

 def get_range(dictionary, begin, end): return {k: v for k, v in dictionary.items() if begin <= k <= end} 
+16
source share

Direct implementation:

 def get_range(d, begin, end): result = {} for (key,value) in d.iteritems(): if key >= begin and key <= end: result[key] = value return result 

One line:

 def get_range2(d, begin, end): return dict([ (k,v) for (k,v) in d.iteritems() if k >= begin and k <= end ]) 
+3
source share

sure that you really want an OrderedDict , you can also use enumerate :

 #!/usr/bin/env python def get_range(d, begin, end): return dict(e for i, e in enumerate(d.items()) if begin <= i <= end) if __name__ == '__main__': print get_range({"a":"b", "c":"d", "e":"f"}, 0, 1) 

exit:

 {'a': 'b', 'c': 'd'} 

ps: I use 0, 1 as range values, but you should use 0, 2 to label the "first two elements" (and use begin <= i < end as a comparison function

0
source share

As others have noted, Python dictionaries are inherently disordered. However, at any time, a list of their current keys or key pairs, values โ€‹โ€‹can be obtained using the keys() or items() methods.

The potential problem with using these lists is that not only their contents, but also the order in which it is returned will probably change if the dictionary has been changed (or changed) since the last time it was used. This means that, as a rule, you cannot store and reuse a list if you do not update it every time the dictionary changes, in case you need it.

To make this approach more manageable, you can combine a dictionary and an auxiliary list into a new derived class that synchronizes between them, and also provides a get_range() method that uses the current contents of the list. The following is sample code showing how to do this. This is based on the ideas I got from the code in this ActiveState Python recipe .

 class dict_with_get_range(dict): def __init__(self, *args, **kwrds): dict.__init__(self, *args, **kwrds) self._list_ok = False def _rebuild_list(self): self._list = [] for k,v in self.iteritems(): self._list.append((k,v)) self._list_ok = True def get_range(self, begin, end): if not self._list_ok: self._rebuild_list() return dict(self._list[i] for i in range(begin,end+1)) def _wrapMutatorMethod(methodname): _method = getattr(dict, methodname) def wrapper(self, *args, **kwrds): # Reset 'list OK' flag, then delegate to the real mutator method self._list_ok = False return _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 main idea is to derive a new class from dict , which also has a list of internal contents for use by the new get_range() method, which it provides that regular dictionary objects do not. To minimize the need to update (or even create) this internal list, it also has a flag indicating whether this list is updated or not, and only checks it and rebuilds the list when necessary.

To support the flag, each legacy dictionary method that potentially modifies (or alters) the contents of the dictionary is โ€œwrappedโ€ by an auxiliary function, discards the flag, and then binds to standard dictionary methods for actual operation. Installing them in a class is simply a matter of entering the names of the methods in one of the two lists, and then transferring them to one auxiliary utility immediately after creating the class.

0
source share

All Articles