【问题标题】:python: how to get a subset of dictpython:如何获取dict的子集
【发布时间】:2026-02-01 15:10:01
【问题描述】:

我有一个包含很多元素的字典,我想编写一个函数,可以返回给定索引范围内的元素(将字典视为数组):

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)

我不在乎排序... 其实我正在实现服务器端分页...

【问题讨论】:

  • by indexes 你的意思是键???
  • @singularity:看看OP过去的问题*.com/questions/4181367/…你应该是对的。
  • 不,不是按键,只是经过一些排序(或根本没有排序),我想要字典的第一个/最后一个/中间部分...
  • 字典没有任何顺序,所以你不能得到'first' 2个元素。
  • @Bin Chen:我认为@singularity 的意义在于字典{"a":"b", "c":"d", "e":"f"}{"e":"f", "c":"d", "a":"b"}相同的。前两个元素是什么?

标签: python


【解决方案1】:

编辑:字典没有排序。只要您修改了字典,就不可能使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}

【讨论】:

  • 调用变量 the_dict 等是变量的“正确”样式。
  • @Chris:好的。 (重命名为dictionary所以双方都很高兴:))
  • 第二个示例与第一个示例不同——第一个过滤键,第二个对项目列表进行切片。
【解决方案2】:

直接实施:

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 ])

【讨论】:

  • 哎呀,不要调用参数dict...同样key &gt;= begin and key &lt;= end会像begin &lt;= key &lt;= end一样简洁。很酷的 Python 功能,你可以这样做。
  • 跟着 OP... 我同意错误的变量名。
【解决方案3】:

放心,你真正想要的是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 &lt;= i &lt; end作为比较函数

【讨论】:

    【解决方案4】:

    正如其他人所提到的,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() 方法使用,它提供了常规字典对象没有的方法。为了尽量减少更新(甚至创建)这个内部列表的需要,它还有一个标志来指示列表是否是最新的,并且只在必要时检查它并重建列表。

    为了维护标志,每个可能更改(或变异)字典内容的继承字典方法都使用帮助函数“包装”,重置标志,然后链接到普通字典方法以实际执行操作。将它们安装到类中只需将方法的名称放在两个列表之一中,然后在创建类后立即将它们一次传递给辅助实用程序。

    【讨论】: