我有一个包含许多元素的dict,我想编写一个可以返回给定索引范围内的元素的函数(将dict视为数组):
get_range(dict, begin, end):
return {a new dict for all the indexes between begin and end}
如何做到这一点?
编辑:我不是要求使用密钥过滤器......例如)
{"a":"b", "c":"d", "e":"f"}
get_range(dict, 0, 1) returns {"a":"b", "c":"d"} (the first 2 elements)
我不在乎排序...... 实际上我正在实现服务器端分页...
答案 0 :(得分:16)
修改:未订购字典。每当修改字典时,都不可能使get_range
返回相同的切片。如果您需要确定性结果,请替换dict
with a collections.OrderedDict
。
无论如何,你可以获得切片using itertools.islice
:
import itertools
def get_range(dictionary, begin, end):
return dict(itertools.islice(dictionary.iteritems(), begin, end+1))
按键过滤的上一个答案保留在下面:
使用@ Douglas'算法,我们可以使用生成器表达式来简化它:
def get_range(dictionary, begin, end):
return dict((k, v) for k, v in dictionary.iteritems() if begin <= k <= end)
顺便说一句,不要使用dict
作为变量名,正如您在此处所见dict
是字典的构造函数。
如果您使用的是Python 3.x,则可以直接使用字典理解。
def get_range(dictionary, begin, end):
return {k: v for k, v in dictionary.items() if begin <= k <= end}
答案 1 :(得分:3)
直接实施:
def get_range(d, begin, end):
result = {}
for (key,value) in d.iteritems():
if key >= begin and key <= end:
result[key] = value
return result
一行:
def get_range2(d, begin, end):
return dict([ (k,v) for (k,v) in d.iteritems() if k >= begin and k <= end ])
答案 2 :(得分:1)
请确保您真正想要的是OrderedDict
,您还可以使用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)
输出:
{'a': 'b', 'c': 'd'}
ps:我允许您使用0, 1
作为范围值,但您应该使用0, 2
来签署“前两个元素”(并使用begin <= i < end
作为比较函数
答案 3 :(得分:0)
正如其他人所提到的,在Python中,词典本质上是无序的。但是,在任何给定时刻,可以使用其keys()
或items()
方法获取其当前键或键值对的列表。
使用这些列表的一个潜在问题是,如果字典自上次使用以来已被修改(或变异),那么它们的内容以及返回的顺序可能会有所不同。这意味着您通常无法存储和重复使用该列表,除非您每次更改字典时都更新它,以防万一您需要它。
为了使这种方法更易于管理,您可以将字典和辅助列表组合到一个新的派生类中,该类负责两者之间的同步,并提供使用列表当前内容的get_range()
方法。下面是示例代码,说明如何完成此操作。它基于我从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'}
基本思想是从dict
派生一个新类,该类还有一个内部内容列表供它提供的常规字典对象不提供的新get_range()
方法使用。为了最小化更新(甚至创建)此内部列表的需要,它还有一个标志,指示列表是否是最新的,并且只检查它并在必要时重建列表。
为了维护该标志,每个继承的字典方法可能会更改(或改变)字典的内容,并使用辅助函数“包装”,重置标志,然后链接到普通字典方法以实际执行操作。将它们安装到类中只需将方法的名称放在两个列表中的一个列表中,然后在创建类之后立即将它们一次传递给辅助实用程序。