Перемещение и изменение древовидного списка структуры 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 для GAE
  • как печатать удобную покерную руку в python?
  • Какая лучшая технология для подключения от Linux к MS SQL Server с помощью python? ODBC?
  • Как проверить правильность ссылочного свойства в Appengine?
  • Механизм авторизации на основе ролей для приложения GAE
  • dict.fromkeys указывают на один и тот же список
  • хороший питон для компилятора exe?
  • Неожиданное значение функции floor () в python
  • Python - лучший язык программирования в мире.