208 votes

Comment créer des dictées imbriquées en Python ?

J'ai deux fichiers CSV : "Données" et "Cartographie" :

  • Le fichier 'Mapping' comporte 4 colonnes : Device_Name , GDN , Device_Type et Device_OS . Les quatre colonnes sont remplies.
  • Le fichier "Data" comporte les mêmes colonnes, avec les éléments suivants Device_Name et les trois autres colonnes sont vides.
  • Je veux que mon code Python ouvre les deux fichiers et pour chaque Device_Name dans le fichier de données, faire correspondre son GDN , Device_Type et Device_OS du fichier Mapping.

Je sais comment utiliser dict lorsque seulement 2 colonnes sont présentes (1 est nécessaire pour être mappée) mais je ne sais pas comment accomplir ceci lorsque 3 colonnes doivent être mappées.

Voici le code à l'aide duquel j'ai essayé de réaliser le mapping 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 Attribute Error .

Après quelques recherches, je pense que je dois créer un dict imbriqué, mais je n'ai aucune idée de la manière de le faire.

423voto

Inbar Rose Points 13033

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

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

Vous pouvez également utiliser un defaultdict de la 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 le remplir comme vous le souhaitez.

Je recommanderais dans votre code quelque chose comme les suivantes :

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 que le code ci-dessus rend la question confuse. Mon problème en bref : I J'ai 2 fichiers a.csv b.csv, a.csv a 4 colonnes i j k l, b.csv a aussi ces colonnes. i est une sorte de colonne clé pour ces csv. La colonne j k l est vide dans a.csv. est vide dans a.csv mais remplie dans b.csv. Je veux faire correspondre les valeurs des colonnes j k l en utilisant 'i' comme colonne clé de b.csv vers un fichier a.csv.

Ma suggestion serait la suivante 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:]))

Veuillez noter cependant que pour l'analyse des fichiers csv, il y a une fonction module csv .

69voto

Junchen Points 866

UPDATE : Pour une longueur arbitraire d'un dictionnaire imbriqué, allez sur cette réponse .

Utilisez la fonction defaultdict des collections.

Haute performance : "if key not in dict" est très coûteux lorsque l'ensemble de données est grand.

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

37voto

user1068490 Points 61

Pour des niveaux arbitraires d'imbrication :

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

4voto

Gerard G Points 91

Il est important de se rappeler que lors de l'utilisation de defaultdict et de modules dict imbriqués similaires tels que nested_dict La recherche d'une clé inexistante peut créer par inadvertance une nouvelle entrée de clé dans le dict et causer beaucoup de dégâts.

Voici un exemple en Python3 avec nested_dict module :

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

4voto

XerCis Points 161
pip install addict

from addict import Dict

mapping = Dict()
mapping.a.b.c.d.e = 2
print(mapping)  # {'a': {'b': {'c': {'d': {'e': 2}}}}}

Références :

  1. easydict GitHub
  2. addict GitHub

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X