如何在 Python 中创建嵌套的 dict?

我有2个 CSV 文件: “数据”和“映射”:

  • 映射文件有4列: Device_NameGDNDevice_TypeDevice_OS
  • “数据”文件具有相同的列,其中填充了 Device_Name列,其他三列为空。
  • 我希望我的 Python 代码同时打开这两个文件以及 Data 文件中的每个 Device_Name,从 Mapping 文件映射它的 GDNDevice_TypeDevice_OS值。

我知道如何在只有2个列的情况下使用 dict (需要映射1个列) ,但是我不知道如何在需要映射3个列的情况下实现这一点。

下面是我试图用来完成 Device_Type映射的代码:

x = dict([])
with open("Pricing Mapping_2013-04-22.csv", "rb") as in_file1:
file_map = csv.reader(in_file1, delimiter=',')
for row in file_map:
typemap = [row[0],row[2]]
x.append(typemap)


with open("Pricing_Updated_Cleaned.csv", "rb") as in_file2, open("Data Scraper_GDN.csv", "wb") as out_file:
writer = csv.writer(out_file, delimiter=',')
for row in csv.reader(in_file2, delimiter=','):
try:
row[27] = x[row[11]]
except KeyError:
row[27] = ""
writer.writerow(row)

它返回 Attribute Error

经过一些研究,我认为我需要创建一个嵌套结构,但我不知道如何做到这一点。

466943 次浏览

嵌套字典就是字典中的字典,非常简单。

>>> d = {}
>>> d['dict1'] = {}
>>> d['dict1']['innerkey'] = 'value'
>>> d['dict1']['innerkey2'] = 'value2'
>>> d
{'dict1': {'innerkey': 'value', 'innerkey2': 'value2'}}

您还可以使用 collections包中的 defaultdict来帮助创建嵌套字典。

>>> import collections
>>> d = collections.defaultdict(dict)
>>> d['dict1']['innerkey'] = 'value'
>>> d  # currently a defaultdict type
defaultdict(<type 'dict'>, {'dict1': {'innerkey': 'value'}})
>>> dict(d)  # but is exactly like a normal dictionary.
{'dict1': {'innerkey': 'value'}}

你想怎么填充就怎么填充。

我建议在你的代码 喜欢的东西下面:

d = {}  # can use defaultdict(dict) instead


for row in file_map:
# derive row key from something
# when using defaultdict, we can skip the next step creating a dictionary on row_key
d[row_key] = {}
for idx, col in enumerate(row):
d[row_key][idx] = col

根据你的 评论:

上面的代码可能会混淆这个问题 有2个文件 a.csv b.csv,a.csv 有4列 i j k l,b.csv 也有 I 是这些 csvs’. jkl 列的键列 在 a.csv 中为空,但在 b.csv 中填充 L 列使用‘ i’作为键列,从 b.csv 到 a.csv 文件

我的建议是 喜欢这样(不使用默认值) :

a_file = "path/to/a.csv"
b_file = "path/to/b.csv"


# read from file a.csv
with open(a_file) as f:
# skip headers
f.next()
# get first colum as keys
keys = (line.split(',')[0] for line in f)


# create empty dictionary:
d = {}


# read from file b.csv
with open(b_file) as f:
# gather headers except first key header
headers = f.next().split(',')[1:]
# iterate lines
for line in f:
# gather the colums
cols = line.strip().split(',')
# check to make sure this key should be mapped.
if cols[0] not in keys:
continue
# add key to dict
d[cols[0]] = dict(
# inner keys are the header names, values are columns
(headers[idx], v) for idx, v in enumerate(cols[1:]))

但是请注意,对于解析 csv 文件,有一个 CSV 模块

更新: 对于任意长度的嵌套字典,转到 这个答案

使用集合中的 default 函数。

高性能: 当数据集很大时,“ if key not in dict”是非常昂贵的。

低维护: 使代码更具可读性,并且易于扩展。

from collections import defaultdict


target_dict = defaultdict(dict)
target_dict[key1][key2] = val

对于任意级别的嵌套:

In [2]: def nested_dict():
...:     return collections.defaultdict(nested_dict)
...:


In [3]: a = nested_dict()


In [4]: a
Out[4]: defaultdict(<function __main__.nested_dict>, {})


In [5]: a['a']['b']['c'] = 1


In [6]: a
Out[6]:
defaultdict(<function __main__.nested_dict>,
{'a': defaultdict(<function __main__.nested_dict>,
{'b': defaultdict(<function __main__.nested_dict>,
{'c': 1})})})

在使用 default 和类似的嵌套 dict 模块(如 nested_dict)时,一定要记住,查找一个不存在的密钥可能会在不经意间在 dict 中创建一个新的密钥条目,从而造成很大的破坏。

下面是一个使用 nested_dict模块的 Python 3示例:

import nested_dict as nd
nest = nd.nested_dict()
nest['outer1']['inner1'] = 'v11'
nest['outer1']['inner2'] = 'v12'
print('original nested dict: \n', nest)
try:
nest['outer1']['wrong_key1']
except KeyError as e:
print('exception missing key', e)
print('nested dict after lookup with missing key.  no exception raised:\n', nest)


# Instead, convert back to normal dict...
nest_d = nest.to_dict(nest)
try:
print('converted to normal dict. Trying to lookup Wrong_key2')
nest_d['outer1']['wrong_key2']
except KeyError as e:
print('exception missing key', e)
else:
print(' no exception raised:\n')


# ...or use dict.keys to check if key in nested dict
print('checking with dict.keys')
print(list(nest['outer1'].keys()))
if 'wrong_key3' in list(nest.keys()):


print('found wrong_key3')
else:
print(' did not find wrong_key3')

产出为:

original nested dict:   {"outer1": {"inner2": "v12", "inner1": "v11"}}


nested dict after lookup with missing key.  no exception raised:
{"outer1": {"wrong_key1": {}, "inner2": "v12", "inner1": "v11"}}


converted to normal dict.
Trying to lookup Wrong_key2


exception missing key 'wrong_key2'


checking with dict.keys


['wrong_key1', 'inner2', 'inner1']
did not find wrong_key3

如果你想为一个路径创建一个嵌套的字典,给出一个列表(任意长度) ,并对路径末尾可能存在的一个条目执行一个函数,这个方便的小递归函数非常有用:

def ensure_path(data, path, default=None, default_func=lambda x: x):
"""
Function:


- Ensures a path exists within a nested dictionary


Requires:


- `data`:
- Type: dict
- What: A dictionary to check if the path exists
- `path`:
- Type: list of strs
- What: The path to check


Optional:


- `default`:
- Type: any
- What: The default item to add to a path that does not yet exist
- Default: None


- `default_func`:
- Type: function
- What: A single input function that takes in the current path item (or default) and adjusts it
- Default: `lambda x: x` # Returns the value in the dict or the default value if none was present
"""
if len(path)>1:
if path[0] not in data:
data[path[0]]={}
data[path[0]]=ensure_path(data=data[path[0]], path=path[1:], default=default, default_func=default_func)
else:
if path[0] not in data:
data[path[0]]=default
data[path[0]]=default_func(data[path[0]])
return data

例如:

data={'a':{'b':1}}
ensure_path(data=data, path=['a','c'], default=[1])
print(data) #=> {'a':{'b':1, 'c':[1]}}
ensure_path(data=data, path=['a','c'], default=[1], default_func=lambda x:x+[2])
print(data) #=> {'a': {'b': 1, 'c': [1, 2]}}

这是一个空的嵌套列表,从中我们可以将数据附加到空的 dict 中

ls = [['a','a1','a2','a3'],['b','b1','b2','b3'],['c','c1','c2','c3'],
['d','d1','d2','d3']]

这意味着在 data _ dict 中创建四个空的 dict

data_dict = {f'dict{i}':{} for i in range(4)}
for i in range(4):
upd_dict = {'val' : ls[i][0], 'val1' : ls[i][1],'val2' : ls[i][2],'val3' : ls[i][3]}


data_dict[f'dict{i}'].update(upd_dict)


print(data_dict)

输出

< p > {‘ dic0’: {‘ val’: ‘ a’,‘ val1’: ‘ a1’,‘ val2’: ‘ a2’,‘ val3’: ‘ a3’} , ‘ dict1’: {‘ val’: ‘ b’,‘ val1’: ‘ b1’,‘ val2’: ‘ b2’,‘ val3’: ‘ b3’} ,‘ dict2’: {‘ val’: ‘ c’,‘ val1’: ‘ c1’,‘ val2’: ‘ c2’,‘ val3’: ‘ c3’} ,‘ dict3’: {‘ val’: ‘ d’,‘ val1’:’d 1’,‘ val2’:’d 2’,‘ val3’:’d 3’}

#in jupyter
import sys
!conda install -c conda-forge --yes --prefix {sys.prefix} nested_dict
import nested_dict as nd
d = nd.nested_dict()

现在可以使用‘ d’来存储嵌套的键值对。

travel_log = {
"France" : {"cities_visited" : ["paris", "lille", "dijon"], "total_visits" : 10},
"india" : {"cities_visited" : ["Mumbai", "delhi", "surat",], "total_visits" : 12}
}
pip install addict
from addict import Dict


mapping = Dict()
mapping.a.b.c.d.e = 2
print(mapping)  # {'a': {'b': {'c': {'d': {'e': 2}}}}}

参考文献:

  1. 易学 GitHub
  2. GitHub 成瘾者 GitHub 成瘾者 GitHub 成瘾者 GitHub 成瘾者 GitHub 成瘾者 GitHub 成瘾者 GitHub 成瘾者 GitHub 成瘾者 GitHub 成瘾者 GitHub 成瘾者 GitHub 成瘾者 GitHub 成瘾者 GitHub 成瘾者 GitHub 成瘾者 GitHub

您可以初始化一个空 NestedDict,然后为新键赋值。

from ndicts.ndicts import NestedDict


nd = NestedDict()
nd["level1", "level2", "level3"] = 0
>>> nd
NestedDict({'level1': {'level2': {'level3': 0}}})

指控在 Pypi

pip install ndicts