【问题标题】:Obtaining list (or set) of unique values in nested dictionary获取嵌套字典中唯一值的列表(或集合)
【发布时间】:2016-03-10 16:42:27
【问题描述】:

我想知道是否有更优雅/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)

【问题讨论】:

    标签: python list dictionary set


    【解决方案1】:

    您可以使用 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】:

      使用set comprehension

      >>> {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'}
      

      您甚至可以使用Padraic 提到的operator.itemgetter

      >>> 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'}
      

      【讨论】:

      • 谢谢!如果值是一个列表而不是一个字符串呢? python中是否有“唯一”列表之类的东西?
      • @laszlopanaflex 不确定我是否理解您的问题。但如果你想要一个列表,请将{} 更改为[]。它被称为列表推导。该集合是一种数据结构,其中值是唯一的,列表不是。另见How do you remove duplicates from a list in Python whilst preserving order?。希望对您有所帮助。
      • 如果你得到一份食物清单而不是单一食物:set(reduce(lambda x,y:x + y, [orders[i]['food'] for i in orders], []))
      • 我的意思是,假设不是 'pizza' 和 'taco' 我有 ['pizza', 'taco'] 和 ['pizza', 'taco'],即每个人都想要这两个项目。所以,我想知道的是,如果你看到我在说什么,你能获得唯一列表
      • @laszlopanaflex 为此,您需要添加另一个集成级别。您还需要将它们添加到集合中。
      【解决方案3】:

      如果您收集的值是“不可变的”,您可以使用集合推导来收集不同的值。 @BhargavRao 已经提出了这个建议,但这里有一个更清洁的解决方案:

      foods = set( val["food"] for val in orders.values() )
      

      您还询问(在评论中)如果值是列表该怎么办。如果值为["pizza", "taco"],我假设您希望集合中的"pizza""taco",而不是["pizza", "taco"] 作为元素。如果 some 元素是列表而有些是字符串,这有点棘手(糟糕的设计;最好在任何地方都有列表,即使它只是一个元素),所以我会逐步进行,如下所示:

      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
      

      【讨论】:

        【解决方案4】:

        如果你得到一份食物清单而不是单一食物:

        set(reduce(lambda x,y:x + y, [orders[i]['food'] for i in orders], []))
        

        【讨论】:

          猜你喜欢
          • 2016-12-27
          • 2016-01-07
          • 2021-05-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-04-26
          相关资源
          最近更新 更多