Python как индексировать многомерный массив строковым ключом, например dict
Я хотел бы совместить функциональность и NumPy это array
С , а именно создание многомерного массива, который может быть индексирован строками.
например, я мог бы сделать это:
dict_2d = {'a': {'x': 1, 'y': 2},
'b': {'x': 3, 'y': 4}}
print dict_2d['a','y'] # returns 2
Я знаю, что мог бы сделать dict_2d['a']['x']
но в долгосрочной перспективе я хотел бы иметь возможность рассматривать их как массивы numpy, включая матричное умножение и такое, и это невозможно с многослойными диктами.
его также не так сложно написать простой версия класса, где я просто использую класс для преобразования всех строк в индексы int, а затем использую numpy, но я хотел бы использовать то, что уже существует, если это возможно.
Edit: мне не нужна невероятная производительность. Я буду работать с массивами 10x10. Моя цель - сделать написание кода простым и надежным. Работа с массивами numpy не сильно отличается от записи в Fortran. Я провел достаточно своей жизни, отслеживая ошибки индексирования Fortran...
3 ответов
возможно, вы ищете панды, который предоставляет удобные типы данных, которые обертывают массивы numpy, позволяя вам обращаться к строкам и столбцам по имени, а не только по номеру.
Я не люблю давать готовые ответы - но я думаю, что это займет гораздо больше времени, чтобы объяснить это по-английски -
основная идея fetch объекты, как numpy делает, чтобы настроить __getitem__
method-значения, разделенные запятыми, представлены методу как кортежи - вы просто используете значения в кортежах в качестве индексов для ваших вложенных словарей последовательно.
помимо этого, Python упростил создание полнофункциональных эквивалентов dict с помощью коллекции.abc классы: если вы реализуете минимальный набор методов при inhetiring из collections[.abc].MutableMapping
, все поведение словаря эмулируется - (__getitem__, __setitem__, __delitem__, __iter__, __len__
) - тогда это просто вопрос правильной итерации ключевых компонентов и создания новых, пустых, регулярных словарей для хранения необходимых значений.
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))
и вы готовы отправиться:
>>> 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
>>>
обратите внимание, что это реализация высокого уровня, которая будет просто работать, но у вас не будет нигде рядом с оптимизацией уровень вы получите на NumPy с этим-наоборот. Если вам нужно будет выполнять быстрые операции с данными в этих объектах, вы можете проверить "cython" - или прибегнуть к своей идее транспонирования ключей dict в nuemric keys и использовать NumPy (эта идея все еще может выбрать некоторые идеи из этого ответа)