У меня есть список значений следующим образом:

[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]

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

  1. элементы, которые появляются только на правой стороне (все они должны быть вверху списка) -> 7, 8, 9, 4, 2
  2. элементы, которые появляются только на LHS (их можно разместить внизу списка) -> 1, 6
  3. Элементы, которые отображаются как на правой, так и на левой стороне -> 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)
-1
Alk 6 Июн 2019 в 14:20

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)

2
vurmux 6 Июн 2019 в 11:42

Вы можете использовать библиотеку 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]
2
vlemaistre 6 Июн 2019 в 11:34

Этот пример кода Rosetta с топологической сортировкой обрабатывает случай, когда зависимости могут давать несколько подходящих порядков, например показаны элементы, чьи подзаказы все еще соответствуют зависимостям.
Например: если 2 и 3 должны появиться перед 1 и элементы 1, 2, 3, and 4, то порядок 2 относительно 3 и 4 относительно 1, 2 и 3 является переменным.

Код также обнаруживает циклы и имеет примеры выполнения.

0
Paddy3118 6 Июн 2019 в 12:18

Это сортировка? Или просто ходить по графику?

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 

Который, кажется, удовлетворяет всем вашим ограничениям.

0
PaulMcG 6 Июн 2019 в 12:38