访问深度嵌套的 Python 字典的元素

时间:2021-02-25 22:15:37

标签: python dictionary collections nested

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

我尝试将字典变平并尝试对元素进行各种索引访问,但没有成功。

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

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

3 个答案:

答案 0 :(得分:1)

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

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

打印什么

2021-02-01T21:40:00Z

长期的问题是你你正在尝试扁平化你的字典,但是:

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

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

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

答案 1 :(得分:0)

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

答案 2 :(得分:0)

谢谢大家

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

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

我从 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