如何根据任意条件函数过滤字典?

Posted

技术标签:

【中文标题】如何根据任意条件函数过滤字典?【英文标题】:How to filter a dictionary according to an arbitrary condition function? 【发布时间】:2011-02-20 03:10:39 【问题描述】:

我有一本点字典,比如说:

>>> points='a':(3,4), 'b':(1,2), 'c':(5,5), 'd':(3,3)

我想创建一个新字典,其中包含 x 和 y 值小于 5 的所有点,即点 'a'、'b' 和 'd'。

根据the book,每个字典都有items()函数,它返回一个(key, pair)元组的列表:

>>> points.items()
[('a', (3, 4)), ('c', (5, 5)), ('b', (1, 2)), ('d', (3, 3))]

所以我写了这个:

>>> for item in [i for i in points.items() if i[1][0]<5 and i[1][1]<5]:
...     points_small[item[0]]=item[1]
...
>>> points_small
'a': (3, 4), 'b': (1, 2), 'd': (3, 3)

有没有更优雅的方式?我期待 Python 有一些超级棒的 dictionary.filter(f) 函数...

【问题讨论】:

***.com/questions/3420122/… 【参考方案1】:

您可以使用字典推导:

k: v for k, v in points.items() if v[0] < 5 and v[1] < 5

在 Python 2 中,从 2.7 开始:

k: v for k, v in points.iteritems() if v[0] < 5 and v[1] < 5

【讨论】:

点赞!这比Martellis 更通用的方法快两倍多。请注意,您也可以使用视图(如 itemitems,它们不是 dict 项的副本): k: v for k, v in points.viewitems() if v[0] 这里很好地解释了为什么函数调用 dict() 比构造函数/文字语法慢 doughellmann.com/2012/11/… 请记住,iteritems 在 Python 3 中已被删除。但您可以改用 items。它的行为方式与 iteritems 在旧版本中的工作方式相同。 @Datanovice 我相信可以。人们还可以打开一个具有足够详细信息的新问题,以获得更有用的答案;) 一个人打开了一个回答有限的问题,因此一个人求助于阅读尽可能多的问题以获得更好的理解。一个人看到了一个更有知识的人,因此,继续挑选大脑;)我的 Q :***.com/questions/50104127/…【参考方案2】:
dict((k, v) for k, v in points.items() if all(x < 5 for x in v))

如果您使用的是 Python 2,您可以选择调用 .iteritems() 而不是 .items(),并且 points 可能有 很多 个条目。

all(x &lt; 5 for x in v) 如果您确定每个点将始终仅是 2D 的,那么all(x &lt; 5 for x in v) 可能是多余的(在这种情况下,您可能会使用 and 表达相同的约束)但它会正常工作;-)。

【讨论】:

【参考方案3】:
points_small = dict(filter(lambda (a,(b,c)): b<5 and c < 5, points.items()))

【讨论】:

在 Python 2 中使用 iteritems() 代替 items() 在 python 3.5 中,这会返回一个错误:points_small = dict(filter(lambda (a,(b,c)): b 我认为python 3不支持它【参考方案4】:
>>> points = 'a': (3, 4), 'c': (5, 5), 'b': (1, 2), 'd': (3, 3)
>>> dict(filter(lambda x: (x[1][0], x[1][1]) < (5, 5), points.items()))

'a': (3, 4), 'b': (1, 2), 'd': (3, 3)

【讨论】:

太棒了!值得一提的是,这是 Py3,因为 lambda 无法再解包元组参数(参见PEP 3113) 您按字典顺序比较元组,这不是 OP 所要求的。在你的情况下,(3, 10) 点将通过测试:(3, 10) &lt; (5, 5) 是 True,但它是错误的(y 也应该小于 5)。【参考方案5】:
dict((k, v) for (k, v) in points.iteritems() if v[0] < 5 and v[1] < 5)

【讨论】:

【参考方案6】:

我认为 Alex Martelli 的回答绝对是做到这一点的最优雅的方式,但只是想添加一种方式来满足您对 Python 风格的超级棒 dictionary.filter(f) 方法的需求:

class FilterDict(dict):
    def __init__(self, input_dict):
        for key, value in input_dict.iteritems():
            self[key] = value
    def filter(self, criteria):
        for key, value in self.items():
            if (criteria(value)):
                self.pop(key)

my_dict = FilterDict( 'a':(3,4), 'b':(1,2), 'c':(5,5), 'd':(3,3) )
my_dict.filter(lambda x: x[0] < 5 and x[1] < 5)

基本上我们创建一个继承自dict 的类,但添加了过滤器方法。我们确实需要使用.items() 进行过滤,因为在破坏性迭代时使用.iteritems() 会引发异常。

【讨论】:

+1 谢谢,优雅的代码。我真的认为它应该成为标准字典的一部分。【参考方案7】:
dict((k, v) for (k, v) in points.iteritems() if v[0] < 5 and v[1] < 5)

【讨论】:

以上是关于如何根据任意条件函数过滤字典?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 python 或 pandas 根据包含字典列表的列过滤 DataFrame?

在 Shiny 的反应函数中使用 dplyr 条件过滤器

python学习--如何在列表字典集合中根据条件筛选数据

python 利用字典,根据要求的key值条件匹配对应value

python 如何在列表list,字典dict,集合set 中根据条件筛选数据

如何使用条件过滤字典值列表