파이썬에서 중첩 된 dict를 어떻게 작성합니까?


149

'Data'와 'Mapping'이라는 두 개의 CSV 파일이 있습니다.

  • '매핑'파일이 4 열이 : Device_Name, GDN, Device_Type,와 Device_OS. 네 개의 열이 모두 채워집니다.
  • '데이터'파일에는 동일한 열이 있으며 Device_Name열이 채워지고 다른 세 열은 비어 있습니다.
  • 내 파이썬 코드는 두 파일과 각을 열려면 Device_Name, 데이터 파일의지도 GDN, Device_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.

몇 가지 연구를 한 후에 중첩 된 dict을 만들어야한다고 생각하지만이를 수행하는 방법을 모릅니다.


Device_Name열은 두 파일의 키입니다.이 키에서 Device_OS, GDN 및 Device_Type 값을 매핑 파일에서 데이터 파일로 매핑하려고합니다.
atams

당신은 같은 것을 할 수 있기를 원하십니까 row[27] = x[row[11]]["Device_OS"]?
Janne Karila


이것은 반드시 중첩 된 dict가 필요하지 않습니다. pandas, read_csv를 사용 Device_Name하여 인덱스를 만든 다음 인덱스 join에서 두 개의 데이터 프레임을 직접 사용할 수 있습니다 Device_Name.
smci

답변:


307

중첩 된 dict는 사전 내의 사전입니다. 아주 간단한 것입니다.

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

패키지 defaultdict에서 from을 사용하여 collections중첩 된 사전을 쉽게 만들 수 있습니다 .

>>> 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 개의 열 ijkl이 있고 b.csv에도 이러한 열이 있습니다. 나는이 csvs에 대한 일종의 주요 열입니다. jkl 열은 a.csv에서 비어 있지만 b.csv에서는 채워집니다. 'i`를 b.csv에서 a.csv 파일로 키 열로 사용하여 jk ​​l 열의 값을 매핑하고 싶습니다.

내 제안은 다음 같습니다 (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:]))

그러나 csv 파일을 구문 분석하기 위해 csv 모듈이 있습니다.


위의 코드는 질문을 혼란스럽게합니다. 요컨대 내 문제 : 나는이 개 파일을 가지고는 a.csv b.csv, a.csv4 열이 i j k l, b.csv이러한 열이 있습니다. i이 csvs '의 주요 열입니다. j k l열이 비어 a.csv있지만 채워져 있습니다 b.csv. j k l'i`를 b.csv에서 a.csv 파일의 키 열로 사용하여 열 값을 매핑하고 싶습니다 .
atams

64

업데이트 : 중첩 된 사전의 임의 길이는 이 답변으로 이동 하십시오 .

컬렉션에서 defaultdict 함수를 사용하십시오.

고성능 : 데이터 세트가 크면 "키가 dict에없는 경우"가 매우 비쌉니다.

유지 관리 비용 절감 : 코드를 더 읽기 쉽고 쉽게 확장 할 수 있습니다.

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']제공target_dict['1']['2'] KeyError: '2'
haccks

1
당신이 그것을 얻기 전에 가치를 할당해야합니다.
Junchen

24

임의 수준의 중첩 수준 :

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
위의 답변이 두 줄 함수로 수행하는 것처럼 이 답변 에서처럼 한 줄 람다로 수행 할 수도 있습니다 .
Acumenus 2016 년

3

defaultdict와 같은 중첩 된 dict 모듈을 사용할 때 nested_dict존재하지 않는 키를 검색하면 실수로 dict에 새 키 항목이 생성되어 많은 혼란을 초래할 수 있다는 점을 기억해야합니다.

다음은 nested_dict모듈 이있는 Python3 예제입니다 .

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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.