【问题标题】:Python: splitting dictionary into smaller dictionaries by keys (tuple)Python:通过键(元组)将字典拆分为更小的字典
【发布时间】:2018-11-30 15:13:58
【问题描述】:

我有一个字典,其中键是两个整数的元组(x,y),值是字符串。

如何将此字典拆分为更小的字典,其中的拆分取决于y-value 是否大于某个阈值?

例如,假设我有键(字典值无关,所以我在这里省略它们)

(0, 2), (0, 4), (0, 10), (0, 3), (0, 11), (0, 20), (0, 8), (0, 14)

说我有门槛0, 5, 10, 15

那么,一个拆分应该包含一个具有以下键的字典:

(0,2), (0,4), (0,3)

因为y值都大于0,但不大于5。

那么下一个字典应该有键

(0,8)

因为它大于0和5,但不大于10。

然后我们有(0, 10), (0, 11), (0, 14)

因为它大于(或等于)0、5、10,但不是 15。

最后,我们有 (0, 20) 本身。

【问题讨论】:

    标签: python dictionary


    【解决方案1】:

    您可以使用collections.defaultdict,迭代和更新由存储桶边界确定的键。这比创建可变数量的变量更好。

    d = {(0, 2): 1, (0, 4): 2, (0, 10): 3, (0, 3): 4,
         (0, 11): 5, (0, 20): 6, (0, 8): 7, (0, 14): 8}
    
    L = [0, 5, 10, 15, float('inf')]  # include infinite to facilitate later comparisons
    
    from collections import defaultdict
    
    dd = defaultdict(dict)
    
    for k, v in d.items():
        for i, j in zip(L, L[1:]):
            if i <= k[1] < j:
                dd[i].update({k: v})
                break
    
    print(dd)
    
    defaultdict(dict,
                {0: {(0, 2): 1, (0, 3): 4, (0, 4): 2},
                 5: {(0, 8): 7},
                 10: {(0, 10): 3, (0, 11): 5, (0, 14): 8},
                 15: {(0, 20): 6}})
    

    可以通过使用bisect而不是顺序迭代L中的边界来改进算法。

    【讨论】:

      【解决方案2】:

      当然这可以写得更好,但你应该明白。只需遍历 dict,并根据您可以动态定义或生成的各种条件检查键的 y 值。

      thing = {
          (1,2): 'a',
          (2,19): 'b'
      }
      
      d1 = {}
      d2 = {}
      for k, v in thing.items():
          // while iterating through the original dict, write some logic to determine how you want to split up based on the y values.
          if k[1] < 5:
              d1[k] = v
          if k[1] < 10:
              d2[k] = v
      
      print(d1, d2)
      

      【讨论】:

        【解决方案3】:

        这应该可行。

        original_dict = {(0, 2):"a", (0, 4):"b", (0, 10):"c",
         (0, 3):"d", (0, 11):"e", (0, 20):"f", (0, 8):"g", (0, 14):"h"}
        
        thresholds = [0, 5, 10, 15]
        thresholds = sorted(thresholds,reverse=True)
        new_dict_of_dicts = {} #threshold: dict
        for threshold in thresholds:
            new_dict_of_dicts[threshold] = {}
            for key in list(original_dict.keys()):
                if key[1] > threshold:
                    new_dict_of_dicts[threshold][key] = original_dict.pop(key)
        
        print(new_dict_of_dicts) 
        #{15: {(0, 20): 'f'}, 10: {(0, 11): 'e', (0, 14): 'h'}, 5: {(0, 10): 'c', (0, 8): 'g'}, 0: {(0, 2): 'a', (0, 4): 'b', (0, 3): 'd'}}
        

        【讨论】:

          【解决方案4】:

          这个方法对我来说似乎最简单,虽然它肯定不是最快的:

          d1 = {(k1,k2):v for (k1,k2),v in d.items() if 0<k2<=5}
          d2 = {(k1,k2):v for (k1,k2),v in d.items() if 5<k2<=10}
          d3 = {(k1,k2):v for (k1,k2),v in d.items() if 10<k2<=15}
          d4 = {(k1,k2):v for (k1,k2),v in d.items() if 15<k2}
          

          或者像这样组合:

          bounds = 0, 5, 10, 15, 1_000_000
          bounds_dicts = {(b1,b2):{(k1,k2):v for (k1,k2),v in d.items() if b1<k2<=b2}
                          for (b1,b2) in zip(bounds[:-1],bounds[1:])}
          

          同样,这将是低效的。对于每个新字典,字典都会被迭代一次。但是对于小问题,这应该没问题。

          【讨论】:

            猜你喜欢
            • 2013-05-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-01-15
            • 2021-04-15
            • 2017-04-25
            • 2019-11-24
            相关资源
            最近更新 更多