【问题标题】:How to create nested dictionaries with duplicate keys in python如何在python中创建具有重复键的嵌套字典
【发布时间】:2016-07-09 08:24:39
【问题描述】:

我想创建带有嵌套字典和重复键的数据结构。一个详细的例子是:

data['State1']['Landon']['abc Area'] = 'BOB'
data['State1']['Landon']['abc Area'] = 'SAM'
data['State1']['Landon']['xyz Area'] = 'John'
data['State2']['New York']['hjk Area'] = 'Ricky'

for z in data['State1'].keys() , 
# I should get list ['Landon', 'Landon', 'Landon']
for y in data['State1']['Landon'].keys() , 
# I should get list ['abc Area', 'abc Area', 'xyz Area']

目前存储数据我使用了额外的计数器键

data = Autovivification()  
data[state][city][area][counter] = ID  

但是在解析城市/区域的总条目(以及重复项)时,我必须使用嵌套循环直到计数器键。

for city in data['State1'].keys():
  for area in data['State1'][city].keys():
    for counter in data['State1'][city][area].keys():
     for temp in data['State1'][city][area][counter].values():
         cityList.append(city)
         areaList.append(area)

对于嵌套字典,我找到了nosklo发布的以下代码

class AutoVivification(dict):  
    """Implementation of perl's autovivification feature."""  
    def __getitem__(self, item):                
         try:  
            return dict.__getitem__(self, item)  
        except KeyError:   
            value = self[item] = type(self)()  
            return value

对于带有重复键的字典,我找到了 Scorpil 发布的代码

class Dictlist(dict):  
    def __setitem__(self, key, value):  
        try:   
            self[key]   
        except KeyError:   
            super(Dictlist, self).__setitem__(key, [])   
        self[key].append(value)  

如何合并 Autovivification 和 Duplicate class code?或者有没有其他pythonic方式来处理这种情况?

【问题讨论】:

  • 你能解释一下,为什么需要重复的键? 'Area' 是否可以列出,您可以在其中添加多个 ID?
  • @germn : 我已经编辑了这个问题并提供了更多解释,请您检查一下
  • 我更新了答案,添加了新的 items_in 函数,该函数将返回给定数据所需的列表。我确信实现函数以使用 dict/list 结构,然后尝试实现您的新结构会更容易和更清晰。
  • @GerasimovMikhail 非常感谢!!!

标签: python dictionary autovivification


【解决方案1】:

另一个使用defaultdict的例子:

from collections import defaultdict


data = defaultdict(  # State
    lambda: defaultdict(  # City
        lambda: defaultdict(list)  # Area
    )
)


data['State']['City']['Area'].append('area 1')
data['State']['City']['Area'].append('area 2')
data['State']['City']['Area'].append('area 2')


areas = data['State']['City']['Area']
print(areas)  # ['area 1', 'area 2', 'area 2']

total = len(areas)
print(total)  # 3

如何使用此解决方案获取您想要的项目列表:

data['State1']['Landon']['abc Area'].append('BOB')
data['State1']['Landon']['abc Area'].append('SAM')
data['State1']['Landon']['xyz Area'].append('John')
data['State2']['New York']['hjk Area'].append('Ricky')


def items_in(d):
    res = []
    if isinstance(d, list):
        res.extend(d)
    elif isinstance(d, dict):
        for k, v in d.items():
            res.extend([k] * len(items_in(v)))
    else:
        raise ValueError('Unknown data')
    return res


print(items_in(data['State1']))  # ['Landon', 'Landon', 'Landon']
print(items_in(data['State1']['Landon']))  # ['xyz Area', 'abc Area', 'abc Area']
print(items_in(data['State1']['Landon']['abc Area']))  # ['BOB', 'SAM']
print(items_in(data['State1']['Landon']['xyz Area']))  # ['John']

print(items_in(data['State2']))  # ['New York']
print(items_in(data['State2']['New York']))  # ['hjk Area']

【讨论】:

    【解决方案2】:

    一种简单的方法是使其成为一个列表,然后将每个新键添加到列表中:

    Data['State']['City']['Area'] = []
    Data['State']['City']['Area'].append( ID )
    

    【讨论】:

      【解决方案3】:

      您可以将AutoVivication 类替换为自动激活Dictlists 而不是dicts 的类:

      class AutoVivificationDL(Dictlist):  
          """Implementation of perl's autovivification feature."""  
          def __getitem__(self, item):                
               try:  
                  return dict.__getitem__(self, item)  
              except KeyError:   
                  value = self[item] = type(self)()  
                  return value
      

      【讨论】:

      • 谢谢,我已经编辑了更多解释的问题,你能检查一下吗? ,当我使用您的代码时,观察到“运行时错误:调用 Python 对象时超出最大递归深度”。
      • 嗯,没想到。我认为这是 Python 告诉你整个 AutoVivification 的东西不是 Pythonic :) 你最好使用 defaultdict 和常规列表的组合而不是“重复条目”。如果您还没有这样做,您还可以尝试重新考虑是否需要这种超级灵活的数据结构,或者您是否提前对数据有足够的了解以构建具有预定深度的嵌套字典。跨度>
      【解决方案4】:
      Data = {}
      
      
      values = [
          dict(State="CA", City="San Francisco", Area="North", Id="customer1"),
          dict(State="CA", City="San Francisco", Area="Embarcadero", Id="customer1"),
          dict(State="CA", City="San Francisco", Area="North", Id="customer2"),
      
      ]
      
      for v in values:
          #grab the existing entry.  if it doesn't exist, returns a list
          li = Data.setdefault((v["State"],v["City"],v["Area"]),[])
          li.append(v["Id"])
      
      print "Data:%s" % (Data)
      

      输出:

      Data:{('CA', 'San Francisco', 'North'): ['customer1', 'customer2'], ('CA', 'San Francisco', 'Embarcadero'): ['customer1']}
      

      您不仅限于非常简单的 Id 值,您可以将几乎任何您想要的内容添加到列表中。如果您希望在很多地方都这样做,请查看 https://docs.python.org/2/library/collections.html#collections.defaultdict,它有点内置 setdefault。

      实际上,您可以将 ID 添加到字典而不是列表,都是一样的。

      【讨论】:

        猜你喜欢
        • 2020-06-30
        • 1970-01-01
        • 2023-03-20
        • 1970-01-01
        • 2021-02-21
        • 2013-01-07
        • 2023-03-02
        • 2019-02-21
        • 1970-01-01
        相关资源
        最近更新 更多