У меня есть список значений следующим образом:
[1,2,3,4,5,6,7,8,9]
Далее у меня также есть зависимость от следующего формата:
{1 : [2,3], 3: [4], 6: [7,8,9]}
Это означает, что 2,3
должен появиться в списке до 1
, 4
должен появиться в списке до 3
, а 7
, 8
, 9
все должны появиться в списке до 6.
Следовательно, правильная сортировка будет:
[4,2,3,1,7,8,9,6]
На основе этого примера я написал код, который может разбить список на три подмножества:
- элементы, которые появляются только на правой стороне (все они должны быть вверху списка) ->
7
,8
,9
,4
,2
- элементы, которые появляются только на LHS (их можно разместить внизу списка) ->
1
,6
- Элементы, которые отображаются как на правой, так и на левой стороне ->
3
Я борюсь с написанием кода для сортировки предметов, которые попадают в третью категорию:
Что было бы хорошим способом сортировки этих предметов?
РЕДАКТИРОВАТЬ:
supersetR = set({})
supersetL = set({})
for dependency in dependencies:
supersetR = supersetR.union(dependencies[dependency])
supersetL.add(dependency)
onlyL = supersetL - supersetR
onlyR = supersetR - supersetL
LandR = supersetL.intersection(supersetR)
4 ответа
Ваш диктат на самом деле является ориентированным графом. То, что вы хотите получить, называется топологической сортировкой. В Python есть замечательная библиотека для обработки графиков - networkx, в которой ваша проблема может решаться парой строк:
G = nx.DiGraph({1 : [2,3], 3: [4], 6: [7,8,9]})
list(reversed(list(nx.topological_sort(G))))
[2, 4, 3, 1, 8, 9, 7, 6]
Постскриптум Обратите внимание, что ваша проблема может быть решена только в случаях DAG, без каких-либо циклов. Вы не можете упорядочить свой список должным образом в случае этого. Просто представьте себе граф 1->2->3->1
. Все, что вы напишите в список:
[1,2,3]
[2,3,1]
[3,1,2]
Первый и последний узлы будут неправильными, потому что в любом случае они имеют один узел перед ним и один узел после. Вы можете проверить, является ли ваш график DAG с помощью этой функции:
nx.is_directed_acyclic_graph(G)
Вы можете использовать библиотеку networkx
, которая реализует топологическую сортировку. Но ваша проблема, похоже, обратна топологической сортировке, поэтому код будет выглядеть примерно так:
import networkx
dict_sort = {1 : [2,3], 3: [4], 6: [7,8,9]}
graph = networkx.DiGraph(dict_sort)
list(reversed(list(networkx.topological_sort(graph))))
Выход :
[2, 4, 3, 1, 7, 8, 9, 6]
Этот пример кода Rosetta с топологической сортировкой обрабатывает случай, когда зависимости могут давать несколько подходящих порядков, например показаны элементы, чьи подзаказы все еще соответствуют зависимостям.
Например: если 2 и 3 должны появиться перед 1 и элементы 1, 2, 3, and 4
, то порядок 2 относительно 3 и 4 относительно 1, 2 и 3 является переменным.
Код также обнаруживает циклы и имеет примеры выполнения.
Это сортировка? Или просто ходить по графику?
tree = {1 : [2,3], 3: [4], 6: [7,8,9]}
# basic depth-first search of a graph
def dfs(tree, value, depth=0):
if value in tree:
for v in tree[value]:
dfs(tree, v, depth+1)
print(value, end=' ')
# find roots - nodes not listed as subs of any other node
roots = [v for v in tree if not any(v in vv for vv in tree.values())]
for r in roots:
dfs(tree, r)
Дает:
2 4 3 1 7 8 9 6
Который, кажется, удовлетворяет всем вашим ограничениям.
Похожие вопросы
Новые вопросы
python
Python - это многопарадигмальный, динамически типизированный, многоцелевой язык программирования. Он разработан для быстрого изучения, понимания и использования, а также для обеспечения чистого и единообразного синтаксиса. Обратите внимание, что Python 2 официально не поддерживается с 01.01.2020. Тем не менее, для вопросов о Python, связанных с версией, добавьте тег [python-2.7] или [python-3.x]. При использовании варианта Python (например, Jython, PyPy) или библиотеки (например, Pandas и NumPy) включите его в теги.