Перемещение и изменение древовидного списка структуры dict

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

[ {'id': 4, 'children': None}, {'id': 2, 'children': [ {'id': 1, 'children': [ {'id': 6, 'children': None}, {'id': 5, 'children': None} ] }, {'id': 7, 'children': [ {'id': 3, 'children': None} ] } ] } ] 

У меня также есть список выбранных идентификаторов, [4, 5, 6, 7] . Я хочу пройти список и для каждого объекта в списке, добавить selected ключ со значением 1 если он выбран, и 0 если это не так.

В настоящее время я делаю это рекурсивно с помощью этой функции:

 def mark_selected(tree, selected): for obj in tree: obj['selected'] = 1 if obj['id'] in selected else 0 if obj['children'] is not None: obj['children'] = mark_selected(obj['children'], selected) return tree 

Кажется, это работает нормально, но мне было интересно, есть ли более умный способ сделать это, возможно, используя понимание списка или генераторы.

Может ли кто-нибудь придумать более элегантное решение для этого?

3 Solutions collect form web for “Перемещение и изменение древовидного списка структуры dict”

Рекурсия отлично элегантна. Перечисления списков не применяются, поскольку вы изменяете структуру на месте, а не создаете новую последовательность. Что касается генераторов, вы можете написать трафик DFS или BFS.

 def dfs(nodes): if nodes is not None: for node in nodes: yield node for child in dfs(node['children']): yield child for node in dfs(tree): if node['id'] in selected: node['selected'] = true 

Если список идентификаторов для выбора является большим, было бы более эффективным преобразовать его в dict с идентификаторами в качестве ключей, что ускорит поиск ( node['id'] in selected ).

 selected = dict(zip(selected, selected)) 

Поскольку вы работаете, изменяя входной объект, и поскольку объекты имеют ссылочную семантику в Python, вам не нужно возвращать значение или использовать возвращаемое значение на рекурсивном шаге. Кроме того, если вы можете заменить записи «Нет» для детей «[]» (лучше всего использовать кортежи повсюду, а не списки), тогда вы можете упростить логику – вам вообще не нужен базовый случай, потому что вы можете переписывать «пустое дерево», и он просто запускает цикл for для всех нулевых элементов, т. е. ничего не делает – это то, что вы хотите.

И FFS, почему вы не используете встроенный булевский тип Python?

 def mark_selected(tree, selected): for obj in tree: obj['selected'] = obj['id'] in selected mark_selected(obj['children'], selected) 

(О, и вам даже нужно держать детей в определенном порядке? Наличие списка dicts, в котором все содержат ключ «id», является неестественным, имеет смысл иметь dict, где ключи являются идентификаторами, а значения являются dicts без «id».)

Мне нравится использовать замыкания для рекурсивных функций, для этого примера это не имеет большого значения, но вы можете сохранить необходимость передавать «selected» в рекурсивном вызове. В более сложных примерах вы можете сохранить справедливую бит состояния в содержащей функции для использования рекурсией.

 def mark_selected(tree, selected): def recur(tree): for obj in tree: obj['selected'] = 1 if obj['id'] in selected else 0 if obj['children'] is not None: recur(obj['children']) recur(tree) 
  • Создать долгоживущий токен доступа из недолговечного?
  • Python OSError: Нет такого файла или каталога
  • Как написать целые числа в файл
  • Как я могу найти все возможные комбинации списка списков (в Python)?
  • Двоичный массив в python
  • No Module Named ServerSocket
  • есть ли спецификатор множественного формата в Python?
  • Создание списка простых чисел с использованием списка
  • Сканирование списка
  • Python: получить имя файла из filepointer
  • Петля внутри цикла - python
  •  
    Interesting Posts for Van-Lav

    Почему «Нет» имеет тот же эффект, что и «np.newaxis»?

    Освободить дисковое пространство hdf5 после удаления таблицы или узла с помощью pytables или pandas

    Работа с Postgres / PostGIS View в SQLAlchemy

    Получение часового пояса из Lat Long Coordinates?

    Как сделать новые столбцы в dataframe из строки другого столбца?

    Эквивалент string.ascii_letters для строк unicode в python 2.x?

    AttributeError: объект 'unicode' не имеет атрибута '_sa_instance_state'

    Python Tornado – отключить ведение журнала до stderr

    Почему я получаю TypeError: не могу умножить последовательность на non-int типа «float»?

    UnboundLocalError: локальная переменная, указанная перед присваиванием при чтении из файла

    Каков самый быстрый способ найти собственные значения / векторы в python?

    python gspread google spreadsheet поддерживая соединение живым

    Почему я должен использовать Redis, когда у меня есть PostgreSQL в качестве моей базы данных для Django?

    ZeroMQ push socket заставляет клиента не прерываться, когда процесс не прослушивается

    Самый быстрый способ переноса массива Numpy

    Python - лучший язык программирования в мире.