Làm thế nào để bạn tạo ra dict lồng trong Python?


149

Tôi có 2 tệp CSV: 'Dữ liệu' và 'Ánh xạ':

  • Tập tin 'Bản đồ' có 4 cột: Device_Name, GDN, Device_Type, và Device_OS. Tất cả bốn cột được điền.
  • Tệp 'Dữ liệu' có cùng các cột, với Device_Namecột được điền và ba cột còn lại trống.
  • Tôi muốn mã Python của tôi để mở cả hai tập tin và cho mỗi Device_Nametrong file dữ liệu, bản đồ của mình GDN, Device_TypeDevice_OSgiá trị từ tập tin bản đồ.

Tôi biết cách sử dụng dict khi chỉ có 2 cột (cần có 1 bản đồ) nhưng tôi không biết làm thế nào để thực hiện điều này khi 3 cột cần được ánh xạ.

Sau đây là mã sử dụng mà tôi đã cố gắng thực hiện ánh xạ 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)

Nó trở lại Attribute Error.

Sau một số nghiên cứu, tôi nghĩ rằng tôi cần phải tạo ra một chính tả lồng nhau, nhưng tôi không biết làm thế nào để làm điều này.


Device_Namecột là khóa trong cả hai tệp, trên khóa này tôi muốn ánh xạ các giá trị Device_OS, GDN & Device_Type từ ánh xạ tệp sang tệp dữ liệu.
atams

Bạn có muốn làm một cái gì đó như thế row[27] = x[row[11]]["Device_OS"]nào?
Janne Karila


Điều này không cần một chính tả lồng nhau, nhất thiết phải. Bạn có thể sử dụng gấu trúc, read_csv, tạo Device_Namechỉ mục, sau đó bạn có thể trực tiếp joinhai tệp dữ liệu trên chỉ mục của chúng Device_Name.
smci

Câu trả lời:


307

Một dict lồng nhau là một từ điển trong một từ điển. Một điều rất đơn giản.

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

Bạn cũng có thể sử dụng một defaultdicttừ collectionsgói để tạo điều kiện tạo từ điển lồng nhau.

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

Bạn có thể cư trú theo cách bạn muốn.

Tôi muốn giới thiệu trong mã của bạn một cái gì đó như sau:

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

Theo nhận xét của bạn :

có thể ở trên mã đang gây nhầm lẫn cho câu hỏi. Vấn đề của tôi trong tóm tắt: Tôi có 2 tệp a.csv b.csv, a.csv có 4 cột ijkl, b.csv cũng có các cột này. i là loại cột quan trọng cho các csv này '. cột jkl trống trong a.csv nhưng được điền vào b.csv. Tôi muốn ánh xạ giá trị của các cột jk l bằng cách sử dụng 'i` làm cột khóa từ tệp b.csv sang tệp a.csv

Đề xuất của tôi sẽ là một cái gì đó như thế này (không sử dụng defaultdict):

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:]))

Tuy nhiên, xin lưu ý rằng để phân tích tệp csv có mô-đun csv .


có thể ở trên mã đang gây nhầm lẫn cho câu hỏi. Vấn đề của tôi trong tóm tắt: Tôi có 2 tệp a.csv b.csv, a.csvcó 4 cột i j k l, b.csvcũng có các cột này. ilà loại cột chính cho các csv này '. j k lcột trống trong a.csvnhưng dân cư trong b.csv. Tôi muốn ánh xạ giá trị của j k lcác cột bằng cách sử dụng 'i` làm cột khóa từ tệp b.csv sang tệp a.csv.
atams

64

CẬP NHẬT : Đối với độ dài tùy ý của một từ điển lồng nhau, đi đến câu trả lời này .

Sử dụng hàm defaultdict từ các bộ sưu tập.

Hiệu suất cao: "nếu khóa không trong dict" rất tốn kém khi bộ dữ liệu lớn.

Bảo trì thấp: làm cho mã dễ đọc hơn và có thể dễ dàng mở rộng.

from collections import defaultdict

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

3
from collections import defaultdict target_dict = defaultdict(dict) target_dict['1']['2']cho tôitarget_dict['1']['2'] KeyError: '2'
haccks

1
bạn phải gán giá trị trước khi bạn nhận được nó.
Junchen

24

Đối với mức độ lồng nhau tùy ý:

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})})})

2
Câu trả lời trên có tác dụng gì với hàm hai dòng, bạn cũng có thể làm với lambda một dòng, như trong câu trả lời này .
Acumenus

3

Điều quan trọng cần nhớ khi sử dụng defaultdict và các mô-đun dict lồng tương tự như nested_dict, việc tìm kiếm một khóa không tồn tại có thể vô tình tạo ra một mục khóa mới trong dict và gây ra nhiều sự tàn phá.

Đây là một ví dụ Python3 với nested_dictmô-đun:

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

Đầu ra là:

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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.