【问题标题】:Accessing Elements of a Deeply Nested Python Dictionary访问深度嵌套的 Python 字典的元素
【发布时间】:2021-05-28 07:54:24
【问题描述】:

我正在尝试访问字典中键的嵌套元素,但每次尝试遍历它们时都会挂断。

我尝试了扁平化字典并尝试了对元素的各种索引访问器,但没有成功。

目标:访问各个元素,例如:

print(flat['_items'][0]['items']['timestamp'])
print(flat['_items'][0]['items']['value'])

下面是我尝试访问的代码、数据和元素。

def flatten_dict(dd, separator='_', prefix=''):
    return { prefix + separator + k if prefix else k : v
             for kk, vv in dd.items()
             for k, v in flatten_dict(vv, separator, kk).items()
             } if isinstance(dd, dict) else { prefix : dd }  

# Attempt to Flatten the Dictinary
flat = flatten_dict(regDataDict)

for k in flat.keys():
    print(k)   
    
for k, v in flat.items():
    print(k, v)

print(flat['_items'][0]['items']['timestamp']) # TypeError: string indices must be integers
print(flat['_items'][0]) # Prints all Dictionary Keys and Values
print(flat['_items']) # Prints all Dictionary Keys and Values
print(flat['_items']['{items}']) # TypeError: string indices must be integers

字典结构

_items = [
    {'items': [{'errors': None,
                'good': True,
                'questionable': False,
                'substituted': False,
                'timestamp': '2021-02-01T21:40:00Z',
                'value': -180.625427,
                'web_exception': None}],
     'links': {'source': 'https://I1DPOGpIXSBWLkGcEkjIvyMegw8PMMAA'},
     'web_id': 'I1DPOGpIXSBWLkGcEkjIvyMegw8PMMAA'},
    {'items': [{'errors': None,
                'good': True,
                'questionable': False,
                'substituted': False,
                'timestamp': '2021-02-01T21:40:00Z',
                'value': 59.99268,
                'web_exception': None}],
     'links': {'source': 'https://I1DPOGpIXSBWLkGcEkjIvyMegw7_MMAA'},
     'web_id': 'I1DPOGpIXSBWLkGcEkjIvyMegw7_MMAA'},
    {'items': [{'errors': None,
                'good': True,
                'questionable': False,
                'substituted': False,
                'timestamp': '2021-02-01T21:39:56.055191Z',
                'value': 304.8489,
                'web_exception': None}],
     'links': {'source': 'https://I1DPOGpIXSBWLkGcEkjIvyMegwuMYIAA'},
     'web_id': 'I1DPOGpIXSBWLkGcEkjIvyMegwuMYIAA'}
]

【问题讨论】:

    标签: python dictionary collections nested


    【解决方案1】:

    您的直接问题是您的索引与您的结构不匹配。 items 是一个包含字典的列表,而不是字典本身。正确的访问顺序是

    print(regDataDict[0]['items'][0]['timestamp'])
    

    打印出来的

    2021-02-01T21:40:00Z
    

    长期的问题是你你试图压扁你的听写,但是:

    1. 您似乎仍在尝试访问结果,就好像它是原始结构一样;
    2. 您的“展平”例程只是在整个原始值上添加一个空字符串键:您添加一个级别,而不是展平。

    如果您出于某种原因需要展平结构,那么我们需要您指定生成的数据结构,并将您的代码跟踪到问题点。

    特别是,我观察到您有将 dict 作为列表的唯一元素括起来的习惯。这似乎没有提供任何组织利益。如果不出意外,您的数据清理可能应该摆脱这个额外的级别。

    【讨论】:

    • Prune,这很有帮助,但是只有在我去掉字典中 [ ] 结构之前的“_items”字符串时它才有效。对于索引和字符串的所有其他组合,我都会得到相同的错误。我会赞扬你为我指明了正确的方向。还要感谢 blogon 建议对数据进行重组。不幸的是,数据来自我无法控制其输出的 API 服务。
    【解决方案2】:

    OP,作为对 Prune 答案的补充,我是否可以为您的数据建议一种替代结构,其中 web_id 成为键,相关数据是内部字典:

    _items = {
        'I1DPOGpIXSBWLkGcEkjIvyMegw8PMMAA': {
            'errors': None,
            'good': True,
            'questionable': False,
            'substituted': False,
            'timestamp': '2021-02-01T21:40:00Z',
            'value': -180.625427,
            'web_exception': None,
            'source': 'https://I1DPOGpIXSBWLkGcEkjIvyMegw8PMMAA'
        },
        'I1DPOGpIXSBWLkGcEkjIvyMegw7_MMAA': {
            'errors': None,
            'good': True,
            'questionable': False,
            'substituted': False,
            'timestamp': '2021-02-01T21:40:00Z',
            'value': 59.99268,
            'web_exception': None,
            'source': 'https://I1DPOGpIXSBWLkGcEkjIvyMegw7_MMAA'
        },
        'I1DPOGpIXSBWLkGcEkjIvyMegwuMYIAA': {
            'errors': None,
            'good': True,
            'questionable': False,
            'substituted': False,
            'timestamp': '2021-02-01T21:40:00Z',
            'value': 304.8489,
            'web_exception': None,
            'source': 'https://I1DPOGpIXSBWLkGcEkjIvyMegwuMYIAA'
        }
    }
    

    我真的不知道你在做什么,我假设web_id 对每个对象都是唯一的(否则,使用_id 非常具有误导性!),我只是想我会扔这个在那里,因为它会更容易使用。

    假设您的输入数据的结构是一致的,以下是数据清理的方法:

    new_items = {}
    for d in _items:
        new_items[d['web_id']] = {**d['items'][0]}
        new_items[d['web_id']]['source'] = d['links']['source']
    

    如果你想要更简洁的键,你也可以从web_id 中删除公共子字符串:

    
    new_items = {}
    for d in _items:
        new_id = d['web_id'].replace('I1DPOGpIXSBWLkGcEkjIvyMeg', '')
        new_items[new_id] = {**d['items'][0]}
        new_items[new_id]['source'] = d['links']['source']
    

    【讨论】:

      【解决方案3】:

      谢谢大家,

      我修改了我的方法,使其感觉更加面向对象,并避免了很多不必要的字典和列表操作。

      1. 将原始对象转换为字典。
      2. 将字典转换为类。
      3. 以标准 OO 方式访问类成员。

      我在这里借用了 Kien Nguyen Trung 的精彩帖子中的类结构:https://kiennt.com/blog/2012/06/14/python-object-and-dictionary-convertion.html

      class PiStruct(object):
            def __init__(self, **entries):
                  self.__dict__.update(entries)
      
      # convert to PI Response "Class" to Dictionary 
      regDataDict = piItemsStreamValuesR.__dict__
      
      # convert the Dictionary to a Class
      classMembers = PiStruct(**regDataDict)
      
      # Print the Class Members
      for i in range(0,len(classMembers._items)): 
          for n in range(0,len(classMembers._items[i].items)):
              print('Timestamp:', classMembers._items[i].items[i].timestamp)
              print('Reading:', classMembers._items[i].items[i].value)
              print('Name:', classMembers._items[i].name)
      

      原始 PI 对象类型:

      Timestamp: 2021-02-02T16:42:00Z
      Reading: 145.6539
      Name: Sample Name
      Timestamp: 2021-02-02T16:42:00Z
      Reading: 59.9942245
      Name: Sample Name
      Timestamp: 2021-02-02T16:41:20.4717254Z
      Reading: -189.0652
      Name: Sample Name
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-02-11
        • 2021-01-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-01-25
        • 2011-04-17
        相关资源
        最近更新 更多