Python按不同属性过滤对象列表

时间:2017-07-31 11:32:08

标签: python dictionary filtering

我有一个包含多个属性的对象列表。我想根据对象的一个​​属性(country_code)过滤列表,即

当前列表

elems = [{'region_code': 'EUD', 'country_code': 'ROM', 'country_desc': 'Romania', 'event_number': '6880'}, 
{'region_code': 'EUD', 'country_code': 'ROM', 'country_desc':'Romania', 'event_number': '3200'}, 
{'region_code': 'EUD', 'country_code': 'ROM', 'country_desc': 'Romania', 'event_number': '4000'}, 
{'region_code': 'EUD', 'country_code': 'SVN', 'country_desc': 'Slovenia', 'event_number': '6880'}, 
{'region_code': 'EUD', 'country_code': 'NLD', 'country_desc':'Netherlands', 'event_number': '6880'}, 
{'region_code': 'EUD', 'country_code': 'BEL', 'country_desc':'Belgium', 'event_number': '6880'}]

所需清单

elems = [{'region_code': 'EUD', 'country_code': 'ROM', 'country_desc': 'Romania', 'event_number': '6880'}, 
{'region_code': 'EUD', 'country_code': 'SVN', 'country_desc': 'Slovenia', 'event_number': '6880'}, 
{'region_code': 'EUD', 'country_code': 'NLD', 'country_desc': 'Netherlands', 'event_number': '6880'}, 
{'region_code': 'EUD', 'country_code': 'BEL', 'country_desc': 'Belgium', 'event_number': '6880'}]

我可以通过创建一个字典和一个for循环来实现这一点,但我觉得在python中使用filter()或reduce()函数有一种更简单的方法,我只是无法弄清楚如何。

任何人都可以使用内置的python函数简化下面的代码吗?性能是一个重要因素,因为实际数据将是实质性的。

工作代码:

unique = {}
for elem in elems:
  if elem['country_code'] not in unique.keys():
     unique[elem['country_code']] = elem

print(unique.values())

值得注意的是,我也尝试了下面的代码,但它的性能比当前的工作代码还差:

unique = []
for elem in elems:
    if not any(u['country_code'] == elem['country_code'] for u in unique):
        unique.append(elem)

2 个答案:

答案 0 :(得分:3)

我认为你的第一种方法已经非常接近于最佳状态。字典查找很快(就像在set中一样快)并且循环很容易理解,即使有点冗长(通过Python标准),但为了简洁起见,你不应该牺牲可读性。

但是,您可以使用setdefault删除一行,并且您可能希望使用collections.OrderedDict(),以便结果列表中的元素按其原始顺序排列。另请注意,在Python 3中,unique.values()不是列表,而是dict上的视图。

unique = collections.OrderedDict()
for elem in elems:
    unique.setdefault(elem["country_code"], elem)

如果您真的,确实想要使用reduce,您可以使用空dict作为初始值设定项,然后使用d.setdefault(k,v) and d设置值(如果不存在)并返回修改后的字典。

unique = reduce(lambda unique, elem: unique.setdefault(elem["country_code"], elem) and unique,
                elems, collections.OrderedDict())

我只会使用循环。

答案 1 :(得分:2)

我认为你的方法很好。检查elem['country_code'] not in unique而不是elem['country_code'] not in unique.keys()会更好。

但是,这是另一种使用列表理解的方法:

visited = set()
res = [e for e in elems
        if e['country_code'] not in visited
        and not visited.add(e['country_code'])]

最后一点滥用not None == Truelist.add返回None的事实。