【问题标题】:How to group Python dictionary values which are dictionaries themselves如何对作为字典本身的 Python 字典值进行分组
【发布时间】:2019-04-02 16:02:31
【问题描述】:

我想按以下字典的值进行分组:

my_dict = {"Q1": {0: "no", 1: "yes"}, "Q2": {0: "no", 1: "yes"},
           "Q3": {1: "animal", 2: "vehicle"}, Q4: {1: "animal", 2: "vehicle"}}

结果应该是这样的:

result = {("Q1", "Q2"): {0: "no", 1: "yes"}, 
          ("Q3", "Q4"): {1: "animal", 2: "vehicle"}}

我已经尝试过这里列出的解决方案: Grouping Python dictionary keys as a list and create a new dictionary with this list as a value

使用 collections.defaultdict 不起作用,因为结果会暗示我用作分组键的字典最终会成为结果字典的键,如下所示:

result = {{0: "no", 1: "yes"}: ["Q1", "Q2"] , 
          {1: "animal", 2: "vehicle"}: ["Q3", "Q4"]}

当然这不起作用,因为字典的键必须是不可变的。所以我需要一个像frozendict这样的东西,这在python的标准库中是不可用的。

使用 itertools.groupby 也不起作用,因为它需要对数据进行排序。但是 operator.itemgetter 不能对字典进行排序。它说:

TypeError: '<' not supported between instances of 'dict' and 'dict'

因此,我想知道解决这个问题的 Pythonic 方法!谢谢你的帮助:)

【问题讨论】:

    标签: python grouping


    【解决方案1】:

    您可以使用 frozenset 的字典项目来代替 frozendict

    intermediate_dict = defaultdict(list)
    for k, v in my_dict.items():
        intermediate_dict[frozenset(v.items())].append(k)
    
    result = {tuple(v): dict(k) for k, v in intermediate_dict.items()}
    

    输出:

    {('Q1', 'Q2'): {0: 'no', 1: 'yes'}, ('Q3', 'Q4'): {1: 'animal', 2: 'vehicle'}}
    

    上述假设或要求输入排序,在所有情况下都设为O(n),而排序为O(n log n)

    【讨论】:

      【解决方案2】:

      假设字典按值排序,可以使用itertools.groupby

      {tuple(g): k for k, g in groupby(my_dict, key=my_dict.get)}
      

      代码

      from itertools import groupby
      
      my_dict = {"Q1": {0: "no", 1: "yes"}, "Q2": {0: "no", 1: "yes"},
                 "Q3": {1: "animal", 2: "vehicle"}, "Q4": {1: "animal", 2: "vehicle"}}
      
      print({tuple(g): k for k, g in groupby(my_dict, key=my_dict.get)})
      # {('Q1', 'Q2'): {0: 'no', 1: 'yes'}, ('Q3', 'Q4'): {1: 'animal', 2: 'vehicle'}}
      

      【讨论】:

      • 最好将sort dict 指向一个元组列表(sorted 字典在 Py 3.7 之前不是什么东西)。加上key= my_dict.get 我认为有效
      • @Chris_Rands,当然,感谢“get”的事情。 :)
      【解决方案3】:

      所以我需要一个像frozendict这样的东西,它在python的标准库中不可用。

      你能详细说明一下吗?虽然 frozendict 不在语言标准中,但您可以安装一个可用的扩展:https://pypi.org/project/frozendict/

      或者,您可以将字典转换为(键排序的)(key, value) 项的元组,以获得可用作字典键的不可变、规范和可逆表示。

      (请注意,如果字典中可以包含更多可变值,您可能需要递归地执行此操作。)

      编辑:或者对项目使用 freezeset(),正如另一个答案指出的那样。请注意,这还需要递归地确保内部字典的值是不可变的。

      【讨论】:

      • 感谢您的回答!我已经看到pypi上有可用的外部包frozendict,但我不想使用外部包来解决像这样的“小”问题。
      【解决方案4】:

      这是同时使用frozensetgroupby 的另一种方式

      from operator import itemgetter
      from itertools import groupby
      
      first = itemgetter(0)
      second = itemgetter(1)
      
      my_hashes = sorted([(k, hash(frozenset(v))) for k, v in my_dict.items()], key=second)
      
      d = dict()
      
      for k, v in groupby(my_hashes, key=second):
          items = list(v)
          d[tuple(map(first, items))] = my_dict.get(first(first(items)))
      
      print(d)
      
      {('Q3', 'Q4'): {1: 'animal', 2: 'vehicle'}, ('Q1', 'Q2'): {0: 'no', 1: 'yes'}}
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-08-13
        • 1970-01-01
        • 2019-11-16
        • 2023-01-17
        • 1970-01-01
        • 1970-01-01
        • 2014-11-10
        • 1970-01-01
        相关资源
        最近更新 更多