web-dev-qa-db-fra.com

Comment créez-vous un dict imbriqué en Python?

J'ai 2 fichiers CSV. Le premier est un fichier de données et l'autre est un fichier de mappage. Le fichier de mappage comporte 4 colonnes: Device_Name, GDN, Device_Type et Device_OS. Les mêmes colonnes sont présentes dans le fichier de données.

Le fichier de données contient des données avec la colonne Device_Name remplie et les trois autres colonnes vides. Les quatre colonnes sont renseignées dans le fichier de mappage. Je veux que mon code Python ouvre les deux fichiers et que pour chaque Device_Name du fichier de données, mappe ses valeurs GDN, Device_Type et Device_OS à partir du fichier de mappage.

Je sais utiliser dict lorsque seulement 2 colonnes sont présentes (il faut en mapper une), mais je ne sais pas comment faire si 3 colonnes doivent être mappées.

Voici le code à l'aide duquel j'ai essayé de réaliser le mappage de 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)

Il retourne le Atribute Error.

Après quelques recherches, je me suis rendu compte que je devais créer un dict imbriqué, mais je ne sais pas comment faire. S'il vous plaît, aidez-moi à résoudre ce problème ou donnez-moi un coup de pouce dans la bonne direction pour le résoudre. 

110
atams

Un dict imbriqué est un dictionnaire dans un dictionnaire. Une chose très simple.

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

Vous pouvez également utiliser une variable defaultdict à partir du package collections pour faciliter la création de dictionnaires imbriqués.

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

Vous pouvez remplir ce que vous voulez.

Je recommanderais dans votre code quelque chose de comme ce qui suit:

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

Selon votre commentaire :

peut-être au-dessus de code confond la question. Mon problème en bref: I avoir 2 fichiers a.csv b.csv, a.csv a 4 colonnes i j k l, b.csv a aussi ces colonnes. C'est en quelque sorte des colonnes clés pour ces CSV. j k l colonne est vide dans a.csv mais rempli dans b.csv. Je veux mapper les valeurs de j k l colonnes utilisant 'i` comme clé de colonne de b.csv au fichier a.csv

Ma suggestion serait quelque chose comme ceci (sans utiliser 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:]))

Notez cependant que pour analyser les fichiers csv, il existe un module csv .

228
Inbar Rose

UPDATE: pour une longueur arbitraire d'un dictionnaire imbriqué, accédez à cette réponse .

Utilisez la fonction defaultdict des collections. 

Haute performance: "si la clé n'est pas dictée" est très coûteux lorsque l'ensemble de données est volumineux.

Faible maintenance: rend le code plus lisible et peut être facilement étendu.

from collections import defaultdict

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

Pour les niveaux d'imbrication arbitraires:

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

Lors de l’utilisation de defaultdict et de modules dict imbriqués similaires, tels que nested_dict, il est important de noter que la recherche d’une clé inexistante peut créer par inadvertance une nouvelle entrée de clé dans le dict et causer de nombreux dégâts. Voici un exemple Python3 avec 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')

La sortie est:

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
Skysail