#python #dictionary #multidimensional-array #tree #nested
#python #словарь #многомерный массив #дерево #вложенный
Вопрос:
Я хочу создать структуру данных для хранения различных возможных путей через плоскость с разбросанными по ней полигонами. Я решил использовать вложенные многоуровневые словари, чтобы сохранить различные возможные пути, разделяющиеся в фиксированных точках.
Возможным экземпляром такого словаря будет:
path_dictionary = {starting_coordinates:{new_fixpoint1:{new_fixpoint1_1:...}, new_fixpoint2:{new_fixpoint2_1:...}}}
Теперь я хочу продолжить создание этой структуры с новыми путями из последних фиксированных точек, поэтому мне пришлось бы редактировать словарь на разных уровнях вложенности. Мой план состоял в том, чтобы предоставить отсортированный список ключей, который содержит все фиксированные точки заданного пути, и у меня была бы функция для добавления к последнему предоставленному ключу.
Для достижения этой цели я должен был бы иметь доступ к словарю с помощью списка ключей следующим образом:
keylist = [starting_coordinates, new_fixpoint1, new_fixpoint1_1, new_fixpoint1_1_3, ...]
path_dictionary = {starting_coordinates:{new_fixpoint1:{new_fixpoint1_1:...}, new_fixpoint2:{new_fixpoint2_1:...}}}
path_dictionary [keylist [0]] [keylist [1]] [keylist [2]] [...] = additional_fixpoint
Вопрос: Как я могу записать переменный уровень вложенности / глубины в многоуровневом словаре, когда у меня есть список ключей некоторой длины?
Любая помощь очень ценится.
Комментарии:
1. Как вы сказали, это очень широко. Пожалуйста, задайте только один вопрос и покажите, в чем конкретная проблема с тем, что вы пробовали.
2. @mkrieger1 Я удалил дополнительные вопросы, ясна ли моя проблема в остальном?
3. Вероятно, вам следует включить некоторый код, который вы используете, и сообщить нам, в чем именно проблема.
Ответ №1:
Я поиграл с идеей использования нескольких индексов и defaultdict
. И это получилось:
from collections import defaultdict
class LayeredDict(defaultdict):
def __getitem__(self, key):
if isinstance(key, (tuple, list)):
if len(key) == 1:
return self[key[0]]
return self[key[0]][key[1:]]
return super(LayeredDict, self).__getitem__(key)
def __setitem__(self, key, value):
if isinstance(key, (tuple, list)):
if len(key) == 1:
self[key[0]] = value
else:
self[key[0]][key[1:]] = value
else:
super(LayeredDict, self).__setitem__(key, value)
def __init__(self, *args, **kwargs):
super(LayeredDict, self).__init__(*args, **kwargs)
self.default_factory = type(self) # override default
Я не полностью протестировал его, но он должен позволить вам создавать вложенные словари любого уровня и индексировать их с помощью кортежа.
>>> x = LayeredDict()
>>> x['abc'] = 'blah'
>>> x['abc']
'blah'
>>> x[0, 8, 2] = 1.2345
>>> x[0, 8, 1] = 8.9
>>> x[0, 8, 'xyz'] = 10.1
>>> x[0, 8].keys()
[1, 2, 'xyz']
>>> x['abc', 1] = 5
*** TypeError: 'str' object does not support item assignment
К сожалению, нотация расширения (или как она там называется) не поддерживается, но
вы можете просто передать список или кортеж в качестве индекса.
>>> keylist = (0, 8, 2)
>>> x[*keylist]
*** SyntaxError: invalid syntax (<stdin>, line 1)
>>> x[keylist]
1.2345
Кроме того, isinstance(key, (tuple, list))
условие означает, что кортеж не может использоваться в качестве ключа.
Комментарии:
1. Что именно здесь делает super()? Я просмотрел документы python, но я действительно не понял, что он делает… В противном случае я думаю, что это решение, которое я искал, большое вам спасибо!
2.
super(X, self)
привязываетself
экземпляр к классу (классам)X
, от которого наследуется. Поэтому в этом случае убедитесь, что__getitem__
и__setitem__
являются методами, определеннымиdefaultdict
, и не вызывают бесконечного рекурсивного цикла. Всегда пожалуйста!
Ответ №2:
Вы, конечно, можете написать средства доступа для такого вложенного словаря:
def get(d,l):
return get(d[l[0]],l[1:]) if l else d
def set(d,l,v):
while len(l)>1:
d=d[l.pop(0)]
l,=l # verify list length of 1
d[l]=v
(Ни один из них не эффективен для длинных списков; более быстрые версии будут использовать переменный индекс, а не [1:]
или pop(0)
.)
Что касается других подходов, здесь их недостаточно, чтобы выбрать один.
Комментарии:
1. Прежде всего, спасибо за ваш ответ, но я не думаю, что это действительно помогает мне. Если я правильно прочитал код, это выводит значение для заданного списка ключей. Я хочу добавить элементы в этот момент, я не думаю, что это возможно с использованием такого подхода (я пробовал что-то подобное, но рекурсивно)
2. @E.Staikov: разве добавление элементов не просто присваивает ключу в словаре, возвращаемом this
get
для списка ключей до, но не включая добавляемый?