Python'da nasıl iç içe dikteler yaratırsınız?


157

2 CSV dosyam var: "Veri" ve "Eşleme":

  • 'Mapping' dosyası 4 sütun bulunur: Device_Name, GDN, Device_Type, ve Device_OS. Dört sütunun tümü doldurulur.
  • 'Veri' dosyası, Device_Namesütun doldurulmuş ve diğer üç sütun boş olarak aynı sütunları içerir .
  • Benim Python kodu hem dosya ve her biri için açmak istediğiniz Device_Name, Veri dosyasında onun harita GDN, Device_Typeve Device_OSHaritalama dosyadan değer.

Yalnızca 2 sütun varken (1'in eşleştirilmesi gerekir) dict'in nasıl kullanılacağını biliyorum, ancak 3 sütunun eşleştirilmesi gerektiğinde bunu nasıl başaracağımı bilmiyorum.

Eşleştirmeyi gerçekleştirmeye çalıştığım kod şu şekildedir 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)

Dönüyor Attribute Error.

Biraz araştırdıktan sonra, iç içe geçmiş bir söz oluşturmam gerektiğini düşünüyorum, ancak bunu nasıl yapacağım konusunda hiçbir fikrim yok.


Device_Namesütunu her iki dosyanın anahtarıdır, bu anahtarda Device_OS, GDN ve Device_Type değerlerini eşleme dosyasından veri dosyasına eşlemek istiyorum.
02

Böyle bir şey yapabilmek ister row[27] = x[row[11]]["Device_OS"]misin?
Janne Karila


Bu ille de iç içe geçmiş bir dikte gerektirmez. Pandaları kullanabilir, read_csv yapabilir Device_Name, indeksi oluşturabilir ve ardından indekslerindeki joiniki veri çerçevesini doğrudan yapabilirsiniz Device_Name.
smci

Yanıtlar:


320

İç içe geçmiş bir dikte, bir sözlük içindeki bir sözlüktür. Çok basit bir şey.

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

İç içe geçmiş sözlükler oluşturmayı kolaylaştırmak defaultdictiçin collectionspaketten bir de kullanabilirsiniz .

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

Bunu istediğiniz gibi doldurabilirsiniz.

Kodunuzda aşağıdaki gibi bir şey tavsiye ederim :

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

Senin göre comment :

Yukarıdaki kod soruyu karıştırıyor olabilir. Özetle sorunum: 2 dosyam var a.csv b.csv, a.csv'de 4 sütun ijkl var, b.csv'de de bu sütunlar var. i bu csv'ler için anahtar sütunlardır. jkl sütunu a.csv'de boştur, ancak b.csv'de doldurulur. B.csv'den a.csv dosyasına anahtar sütun olarak 'i' kullanarak jk l sütunlarının değerlerini eşlemek istiyorum

Benim önerim şey olurdu gibi (defaultdict kullanmadan) bu:

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

Lütfen csv dosyalarını ayrıştırmak için bir csv modülü olduğunu unutmayın .


yukarıdaki kod soruyu kafa karıştırıcı olabilir. Özetle benim sorun: Ben 2 dosya var a.csv b.csv, a.csv4 sütun var i j k l, b.csvaynı zamanda bu sütun var. ibu csv'ler için anahtar sütunlardır. j k lsütun boş, a.csvancak doldurulmuş b.csv. j k lAnahtar sütun olarak 'i' kullanarak b.csv'den a.csv dosyasına sütun değerlerini eşlemek istiyorum .
2013, 12

66

GÜNCELLEME : İç içe geçmiş bir sözlüğün keyfi uzunluğu için bu yanıta gidin .

Koleksiyonlardan defaultdict işlevini kullanın.

Yüksek performans: "Anahtar dikte değilse", veri kümesi büyük olduğunda çok pahalıdır.

Düşük bakım: kodu daha okunaklı hale getirin ve kolayca genişletilebilir.

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']verir banatarget_dict['1']['2'] KeyError: '2'
haccks

1
anlamadan önce değer atamalısınız.
Junchen

26

Keyfi iç içe geçmişlik düzeyleri için:

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

3
Yukarıdaki cevabın iki satırlı bir fonksiyonla yaptığı şey, bu cevapta olduğu gibi tek satırlı bir lambda ile de yapabilirsiniz .
Acumenus

3

Defaultdict ve nested_dictvarolmayan bir anahtara bakmanın yanlışlıkla diktede yeni bir anahtar girişi oluşturabileceği ve çok fazla hasara yol açabileceği gibi benzer iç içe dikt modüllerini kullanırken hatırlamak önemlidir .

İşte modüllü bir Python3 örneği nested_dict:

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

Çıktı:

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

0

Bir yol için bir liste (rastgele uzunluk) verilen iç içe geçmiş bir sözlük oluşturmak ve yolun sonunda var olabilecek bir öğe üzerinde bir işlev gerçekleştirmek istiyorsanız, bu kullanışlı küçük özyinelemeli işlev oldukça yararlıdır:

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

Misal:

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]}}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.