如何根据任意条件函数过滤字典?
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 < 5 for x in v)
如果您确定每个点将始终仅是 2D 的,那么all(x < 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) < (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?
python 利用字典,根据要求的key值条件匹配对应value