[英]Python - Filter list of dictionaries based on if key value contains all items in another list
I have a list of dictionaries that looks like this, but with around 500 items: 我有一个看起来像这样的字典列表,但是有大约500个条目:
listOfDicts = [{'ID': 1, 'abc': {'123': 'foo'}}, ... {'ID': 7, 'abc': {'123':'foo','456': 'bar'}}]
sampleFilterList = ['123', '456']
I am trying to filter the listOfDicts for all the results where all the values in the sampleFilterList are in the key 'abc' 我正在尝试为所有结果过滤listOfDicts,其中sampleFilterList中的所有值都在键“ abc”中
The result should be a list: 结果应该是一个列表:
[{'ID': 7, 'abc': {'123':'foo','456': 'bar'}}, ...]
I tried [i for i in listOfDicts if a for a in sampleFilterList in i['abc']]
, but I am getting an UnboundLocalError: local variable 'a' referenced before assignment
我试过
[i for i in listOfDicts if a for a in sampleFilterList in i['abc']]
,我却遇到了UnboundLocalError: local variable 'a' referenced before assignment
You need to move the in condition test before the for keyword in the list comprehension and also use get
will be more safe, which returns a default value instead of throwing an error, if you are not sure if all the dictionaries in the list have the keyword abc
: 您需要在移动的状态下测试的关键字列表中的理解,还可以使用
get
将更加安全,它返回默认值,而不是抛出一个错误,如果你不知道,如果在列表中的所有词典中有关键字abc
:
listOfDicts = [{'ID': 1, 'abc': {'123': 'foo'}}, {'ID': 7, 'abc': {'123':'foo','456': 'bar'}}]
sampleFilterList = ['123', '456']
[d for d in listOfDicts if all(s in d.get('abc', {}) for s in sampleFilterList)]
# [{'ID': 7, 'abc': {'123': 'foo', '456': 'bar'}}]
Or if use a set as of @DYZ, you can use issubset
: 或者,如果使用@DYZ的集合,则可以使用
issubset
:
filterSet = set(sampleFilterList)
[d for d in listOfDicts if filterSet.issubset(d.get('abc', {}))]
# [{'ID': 7, 'abc': {'123': 'foo', '456': 'bar'}}]
First, convert your second list to a set for more efficient comparisons: 首先,将第二个列表转换为一组,以进行更有效的比较:
sampleFilterSet = set(sampleFilterList)
Now, compare the 'abc' keys for each list item to the aforesaid set: 现在,将每个列表项的“ abc”键与上述设置进行比较:
[item for item in listOfDicts if not (sampleFilterSet - item['abc'].keys())]
#[{'ID': 7, 'abc': {'123': 'foo', '456': 'bar'}}]
This is the fastest solution. 这是最快的解决方案。 A more Pythonic (but somewhat slower) solution is to use
filter()
: 一种更Pythonic(但速度稍慢)的解决方案是使用
filter()
:
list(filter(lambda item: not (sampleFilterSet - item['abc'].keys()), listOfDicts))
#[{'ID': 7, 'abc': {'123': 'foo', '456': 'bar'}}]
Here is a working version with nested list comprehensions. 这是具有嵌套列表理解的工作版本。 Your problem is that the
a for a in...
is a list comprehension, and needs to be used in constructing a new list. 您的问题是
a for a in...
的a是列表理解,需要在构造新列表时使用。
[i for i in listOfDicts if [a for a in sampleFilterList if a in i['abc']] == sampleFilterList]
for i in zip(listOfDicts):
a = i[0]['abc']
print (a)
or: 要么:
for i in zip(listOfDicts):
if 'abc' in i[0]:
a = i
print (a)
This is an elegant way to do it, I hope it will be useful. 这是一种优雅的方法,希望它会有用。
You could try the following one-liner: 您可以尝试以下单线:
passed_the_filter = [[dictionary_entry for dictionary_entry in list_of_dicts if filter_test in dictionary_entry['abc']] for filter_test in filter]
It is a nested list comprehension that iterates through both the filter and the dictionary list. 这是一个嵌套列表理解,它遍历过滤器和字典列表。 It checks if the filter is a key in the dictionary entries' "abc" value.
它检查过滤器是否是字典条目的“ abc”值中的键。 Your problem was that you used the wrong list comprehension syntax.
您的问题是您使用了错误的列表理解语法。
NB You may want to note that you might not be sure that an element has a "abc" key! 注意:您可能要注意,您可能不确定元素是否具有“ abc”键!
Thank you for reading this. 谢谢您阅读此篇。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.