我想知道是否有更优雅/ pythonic的方式来执行以下操作。假设我有一个嵌套字典:
orders = {'peter': {'food': 'pizza', 'drink': 'soda'}, 'paul': {'food': 'taco', 'drink': 'soda'},'mary': {'food': 'pizza', 'drink': 'water'}}
我希望获得一份包含独特食物的清单。每个人的物品,即每个人。 ['pizza', 'taco']
这是最简单的方法吗?
foodList = []
for i in orders.keys():
foodList.append(orders[i]['food'])
s = set(foodList)
答案 0 :(得分:8)
>>> {orders[i]['food'] for i in orders}
{'pizza', 'taco'}
如果food
的值是列表或元组,则可以在集合理解中使用嵌套循环。
>>> orders = {'peter': {'food': ['pizza','fries'], 'drink': 'soda'}, 'paul': {'food': ['taco'], 'drink': 'soda'}}
>>> {j for i in orders for j in orders[i]['food']}
{'pizza', 'taco', 'fries'}
您甚至可以使用operator.itemgetter
所述的Padraic。
>>> from operator import itemgetter
>>> set(map(itemgetter("food"), orders.values()))
{'pizza', 'taco'}
同样,如果食物的值是一个列表,您可以使用chain
。
>>> from itertools import chain
>>> set(chain(*map(itemgetter("food"), orders.values())))
{'pizza', 'taco', 'fries'}
答案 1 :(得分:0)
您可以使用defaultdict-它解决列表值。
>>>import collections
>>>from collections import defaultdict
>>>d =defaultdict(list)
>>>orders = {'paul': {'food': ['taco', ['sugar']], 'drink': 'soda'}, 'peter': {'food': 'pizza', 'drink': 'soda'}, 'mary': {'food': 'pizza', 'drink': 'water'}}
>>>for i in orders:
d['food'].append(orders[i]['food'])
>>>def flatten(l):#borrowed
for el in l:
if isinstance(el, collections.Iterable) and not isinstance(el, basestring):
for sub in flatten(el):
yield sub
else:
yield el
>>>list(set(flatten(d.values())))
>>>['sugar', 'pizza', 'taco']
答案 2 :(得分:0)
如果你得到食物清单而不是单一食物:
set(reduce(lambda x,y:x + y, [orders[i]['food'] for i in orders], []))
答案 3 :(得分:0)
如果您收集的值是" immutable",您可以使用集合理解来收集不同的值。 @BhargavRao已经提出了这个建议,但这是一个更清洁的解决方案:
foods = set( val["food"] for val in orders.values() )
如果值是列表,您还会(在评论中)询问该怎么做。如果值为["pizza", "taco"]
,我假设您希望集合中包含"pizza"
和"taco"
,而不是["pizza", "taco"]
作为元素。如果某些元素是列表而某些是字符串(设计不佳;在任何地方都有列表,即使它只是一个元素),这有点棘手,所以我会逐步地这样做:
foods = set()
for val in orders.values():
eat = val["food"]
if isinstance(eat, str):
foods.add(eat) # one item
else:
foods.update(eat) # list or tuple