Bagaimana Anda membuat dict bersarang di Python?

149

Saya memiliki 2 file CSV: 'Data' dan 'Pemetaan':

  • File 'Pemetaan' memiliki 4 kolom: Device_Name, GDN, Device_Type, dan Device_OS. Keempat kolom diisi.
  • File 'Data' memiliki kolom-kolom yang sama, dengan Device_Namekolom diisi dan tiga kolom lainnya kosong.
  • Saya ingin kode Python saya untuk membuka kedua file dan untuk setiap Device_Namedalam file data, peta-nya GDN, Device_Typedan Device_OSnilai dari file Pemetaan.

Saya tahu cara menggunakan dict ketika hanya ada 2 kolom (1 harus dipetakan) tetapi saya tidak tahu bagaimana menyelesaikannya ketika 3 kolom perlu dipetakan.

Berikut ini adalah kode yang saya gunakan untuk menyelesaikan pemetaan 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)

Ia kembali Attribute Error.

Setelah meneliti, saya pikir saya perlu membuat dict bersarang, tapi saya tidak tahu bagaimana melakukan ini.

atams
sumber
Device_Namekolom adalah kunci di kedua file, pada kunci ini saya ingin memetakan nilai Device_OS, GDN & Device_Type dari pemetaan file ke file data.
atams
Apakah Anda ingin dapat melakukan sesuatu seperti row[27] = x[row[11]]["Device_OS"]?
Janne Karila
Ini tidak perlu diktat bersarang, tentu saja. Anda bisa menggunakan panda, read_csv, membuat Device_Nameindeks, lalu Anda bisa langsung joindua dataframe pada indeks mereka Device_Name.
smci

Jawaban:

307

Dict bersarang adalah kamus di dalam kamus. Suatu hal yang sangat sederhana.

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

Anda juga dapat menggunakan defaultdictdari collectionspaket untuk memfasilitasi pembuatan kamus bersarang.

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

Anda dapat mengisi itu sesuai keinginan Anda.

Saya akan merekomendasikan sesuatu pada kode Anda seperti berikut:

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

Menurut komentar Anda :

mungkin kode di atas membingungkan pertanyaan. Singkatnya masalah saya: Saya punya 2 file a.csv b.csv, a.csv memiliki 4 kolom ijkl, b.csv juga memiliki kolom ini. i adalah semacam kolom kunci untuk csvs ini. kolom jkl kosong di a.csv tetapi diisi dalam b.csv. Saya ingin memetakan nilai kolom jk l menggunakan 'i` sebagai kolom kunci dari file b.csv ke file acs

Saran saya akan menjadi seperti ini (tanpa menggunakan 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:]))

Harap dicatat, bahwa untuk parsing file csv ada modul csv .

Inbar Rose
sumber
mungkin kode di atas membingungkan pertanyaan. Singkatnya masalah saya: Saya punya 2 file a.csv b.csv, a.csvmemiliki 4 kolom i j k l, b.csvjuga memiliki kolom ini. iadalah jenis kolom kunci untuk csvs ini. j k lkolom kosong a.csvtetapi diisi pada b.csv. Saya ingin memetakan nilai j k lkolom menggunakan 'i` sebagai kolom kunci dari file b.csv ke a.csv.
atams
64

PEMBARUAN : Untuk kamus acak bersarang, pilih jawaban ini .

Gunakan fungsi defaultdict dari koleksi.

Kinerja tinggi: "jika kunci tidak dalam dikt" sangat mahal ketika set data besar.

Pemeliharaan rendah: membuat kode lebih mudah dibaca dan dapat dengan mudah diperpanjang.

from collections import defaultdict

target_dict = defaultdict(dict)
target_dict[key1][key2] = val
Junchen
sumber
3
from collections import defaultdict target_dict = defaultdict(dict) target_dict['1']['2']memberikutarget_dict['1']['2'] KeyError: '2'
haccks
1
Anda harus memberikan nilai sebelum Anda mendapatkannya.
Junchen
24

Untuk tingkat sarang yang sewenang-wenang:

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})})})
andrew
sumber
2
Apa yang dilakukan jawaban di atas dengan fungsi dua baris, Anda juga dapat melakukannya dengan lambda satu baris, seperti dalam jawaban ini .
Acumenus
3

Penting untuk diingat ketika menggunakan defaultdict dan modul dict bersarang serupa seperti nested_dict, bahwa mencari kunci yang tidak ada dapat secara tidak sengaja membuat entri kunci baru di dict dan menyebabkan banyak kekacauan.

Berikut ini adalah contoh Python3 dengan nested_dictmodul:

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

Output adalah:

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
Skysail
sumber