Python comment indexer un tableau multidimensionnel avec une clé de chaîne, comme un dict
je tiens à combiner les fonctionnalités de numpy array
natif de python dict
, à savoir la création d'un tableau multidimensionnel qui peut être indexé avec des chaînes.
Par exemple, je pourrais faire ceci:
dict_2d = {'a': {'x': 1, 'y': 2},
'b': {'x': 3, 'y': 4}}
print dict_2d['a','y'] # returns 2
je sais que je pourrais faire dict_2d['a']['x']
mais à long terme, j'aimerais pouvoir les traiter comme des tableaux numpy incluant la multiplication matricielle et ainsi de suite et ce n'est pas possible avec des dicts superposés.
ce n'est pas non plus si difficile de rédiger un simple version de la classe où j'utilise juste la classe pour convertir toutes les chaînes en Index int et puis utiliser numpy mais je voudrais utiliser quelque chose qui existe déjà si possible.
Edit: je n'ai pas besoin de performances incroyables. Je travaillerai avec des tableaux 10x10. Mon but est de rendre l'écriture du code simple et robuste. Travailler avec numpy arrays n'est pas vraiment très différent que de simplement l'écrire dans Fortran. J'ai passé assez de temps dans ma vie à traquer les Fortran erreurs d'indexation...
3 réponses
je n'aime pas donner prêt à avoir des réponses, mais je pense qu'il faudrait beaucoup plus de temps à expliquer en anglais -
L'idée de base fetch objets la façon dont fait numpy est de personnaliser le __getitem__
méthode-les valeurs séparées par des virgules sont présentées à la méthode en tant que tuples - vous les utilisez juste les valeurs dans le tuple comme index à vos dictionnaires imbriqués dans l'ordre.
au-delà de cela, Python a rendu facile de créer pleinement fonctionnelle dict equivalentes avec le collection.classes abc: si vous mettez en œuvre un ensemble minimal de méthodes lorsque vous inspirez de collections[.abc].MutableMapping
, tous dictionnaire comportement est émulé - (__getitem__, __setitem__, __delitem__, __iter__, __len__
) - alors, c'est juste une question d'itération correcte à travers les composants clés, et de créer de nouveaux dictionnaires vides et réguliers pour stocker les valeurs nécessaires.
try:
from collections import MutableMapping
except ImportError:
# Python3 compatible import
from collections.abc import MutableMapping
class NestedDict(MutableMapping):
def __init__(self, *args, **kw):
self.data = dict(*args, **kw)
def get_last_key_levels(self, key, create=False):
if not isinstance(key, tuple):
key = (key,)
current_data = self.data
for subkey in key:
previous = current_data
current_data = current_data[subkey] if not create else current_data.setdefault(subkey, {})
return previous, current_data, subkey
def __getitem__(self, key):
previous, current_data, lastkey = self.get_last_key_levels(key)
return current_data
def __setitem__(self, key, value):
previous, current_data, lastkey = self.get_last_key_levels(key, True)
previous[lastkey] = value
def __delitem__(self, key):
previous, current_data, lastkey = self.get_last_key_levels(key)
del previous[lastkey]
def __iter__(self):
return iter(self.data)
def __len__(self):
return len(self.data)
def __repr__(self):
return "NestedDict({})".format(repr(self.data))
Et vous êtes prêt à aller:
>>> from nesteddict import NestedDict
>>> x = NestedDict(a={})
NestedDict({'a': {}})
>>> x["a", "b"] = 10
>>> x
NestedDict({'a': {'b': 10}})
>>> x["a", "c", "e"] = 25
>>> x
NestedDict({'a': {'c': {'e': 25}, 'b': 10}})
>>> x["a", "c", "e"]
25
>>>
veuillez noter qu'il s'agit d'une implémentation de haut niveau, qui ne fera que fonctionner, mais vous n'aurez nulle part près de l'optimisation niveau vous obtenez sur engourdi avec cela - au contraire. Si vous avez besoin d'effectuer des opérations de données rapides dans ces objets, vous pouvez peut - être vérifier "cython" - ou recourir à votre idée de transposer les touches dict aux touches nuemric et utiliser NumPy (cette idée pourrait encore choisir quelques idées de cette réponse)
utiliser pandas Disons que le fichier est comme ceci:
de test.csv:
Params, Val1, Val2, Val3
Par1,23,58,412
Par2,56,45,123
Par3,47,89,984
Si vous pouvez faire quelque chose comme ça en python:
import pandas as pd
x = pd.read_csv('test.csv', index_col='Params')
x['Val1']['Par3']
47