Список пути к словарю - PullRequest
0 голосов
/ 15 мая 2018

Я пытаюсь заполнить python dict из списка путей (цель состоит в том, чтобы создать ttk.treview):

paths = ["\\hihi", "\\hihi\\hoho\\huhu", "\\hihi\\hoho\\haha", "\\haha", "\\huhu"]

, и я хочу создать этот словарь (json сериализированный здесь):

{
   "haha": {},
   "hihi": {
       "hoho": {
           "huhu": 0
       },
       "huhu": {
           "haha": 0
       }
   },
   "huhu": {}
}

Каков наилучший способ сделать это?Я попытался с циклом for (рекурсивный цикл?), С пониманием dict и с dpath, но у меня нет действительного результата.

Значение моего кода:

split = paths.split("\\")
del split[0]
dict = {}
?

Большое спасибо заранее

Ответы [ 4 ]

0 голосов
/ 15 мая 2018

Вы можете использовать рекурсию с itertools.groupby:

import itertools
paths = ["\\hihi", "\\hihi\\hoho\\huhu", "\\hihi\\hoho\\haha", "\\haha", "\\huhu"]
new_paths = [list(filter(None, i.split('\\'))) for i in paths]
def update_output(f):
  def wrapper(_d):
    result = f(_d)
    final = lambda x, level = 0:{a:{} if not level and not b else b if not b else final(b, level+1) for a, b in x.items()}
    return final(result)
  return wrapper
@update_output
def full_directory(data):
  def files(d):
    return {a:(lambda x:0 if len(x) == 1 else files([i[1:] for i in filter(lambda y:len(y) != 1 or y[0] != a, x)]))(list(b)) for a, b in itertools.groupby(sorted(d, key=lambda x:x[0]), key=lambda x:x[0])}
  return files(data)

print(full_directory(new_paths))

Вывод:

{'haha': {}, 'hihi': {'hoho': {'haha': 0, 'huhu': 0}}, 'huhu': {}}
0 голосов
/ 15 мая 2018

Я нашел это: http://connor -johnson.com / 2015/02/28 / генерировать древовидную структуру в python /

Работает очень хорошо! Итак, код:

def add(t, path):
   for node in path:
       t = t[node]

Tree = lambda: defaultdict(Tree)
t = Tree()

paths = ["\\hihi", "\\hihi\\hoho\\huhu", "\\hihi\\hoho\\haha", "\\haha", "\\huhu"] 

for path in paths:
   split = path.split("\\")
   del split[0]

   for elt in split:
       add(t, split)


dicts = lambda t: { k:dicts(t[k]) for k in t }

print(json.dumps(dicts(t), indent=4))
0 голосов
/ 15 мая 2018

У меня есть альтернатива рекурсивному решению.Для каждого пути:

  • поместите курсор в корень целевой строки dict
  • последовательность поиска: перемещайте курсор вперед, пока не найдете 0 или отсутствующую часть пути
  • последовательность сборки: добавьте пустой диктет и перемещайте курсор на нем, пока вы не нажмете последнюю часть.
  • последняя часть нуждается в специальной обработке для 0.

Вот код:

def build_paths(paths, d={}):
    for path in paths:
        parts = path.split("\\")[1:] # remove the part before \

        cursor = d
        search = True
        for part in parts[:-1]:
            if search:
                if part not in cursor or not cursor[part]: # not found or 0
                    cursor[part] = {} # set a new dict
                    search = False
            else:
                cursor[part] = {}
            cursor = cursor[part] # advance one level deeper in the dict
        cursor[parts[-1]] = 0 # close with a 0

    return d

Это быстрее, чем рекурсивная версия @xtofl, но не так быстро.С timeit:

iterative: 6.169872568580601
recursive: 17.209112331781498
0 голосов
/ 15 мая 2018

Вы можете использовать defaultdict для этого:

def make_empty_default_dict():
    return defaultdict(make_empty_default_dict)

Определите, как вы добавляете путь:

def add_path(pth, dct):
    if pth:
       subdict = dct[pth[0]]
       return add_path(pth[1:], subdict)
    else:
       return dct

Затем заполните ваш по умолчанию ключ с ключами:

d = make_empty_default_dict()
for path in paths:
  d = add_path(path.split("\\"), d)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...