Изменить многоуровневые словари - PullRequest
1 голос
/ 22 апреля 2019

Я хочу создать структуру данных для хранения различных возможных путей через плоскость с разбросанными по ней многоугольниками.Я решил использовать вложенные многоуровневые словари, чтобы сохранить различные возможные пути разделения в фиксированных точках.

Возможный экземпляр такого словаря будет выглядеть следующим образом:

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

Вопрос: Как я могу записать в переменную уровень вложенности / глубины в мультисловарь высокого уровня, когда у меня есть список ключей некоторой длины?

Любая помощь очень ценится.

Ответы [ 2 ]

0 голосов
/ 22 апреля 2019

Я играл с идеей использования нескольких индексов и 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)) означает, что кортеж нельзя использовать в качестве ключа.

0 голосов
/ 22 апреля 2019

Конечно, вы можете написать методы доступа для такого вложенного словаря:

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

Что касается других подходов, то здесь недостаточно для того, чтобы выбрать один.

...