Если вам необходимо принимать во внимание такие вещи, как, например Сковородкин в комментарии,
[(1, 4), (4, 8), (8, 10)]
(или даже более сложные примеры), то одним из способов эффективного использования будет использование графиков.
Допустим, вы создать орграф (возможно, с помощью networkx
), где каждая пара является узлом, и есть ребро из (а, б) к узлу (C, D), еслиб == гр. Теперь запустите topological sort, итерации в соответствии с порядком и слияния соответственно. Вы должны позаботиться о том, чтобы обрабатывать узлы с двумя (или более) исходящими краями должным образом.
Я понимаю, что в вашем вопросе говорится, что вы хотите избежать циклов из-за большого размера списка. И наоборот, для длинных списков я сомневаюсь, что вы найдете даже эффективное линейное решение времени, используя понимание списка (или что-то в этом роде). Обратите внимание, что вы не можете сортировать список по линейному времени, например.
Вот возможная реализация:
Скажем, мы начинаем с
l = [(1,4), (8,10), (19,25), (10,13), (14,16), (25,30)]
Это упрощает следующее для удаления дубликатов, так что давайте делать:
l = list(set(l))
Теперь, чтобы построить орграф:
import networkx as nx
import collections
g = nx.DiGraph()
Вершины просто пары:
g.add_nodes_from(l)
Чтобы построить края, нам нужен словарь:
froms = collections.defaultdict(list)
for p in l:
froms[p[0]].append(p)
Теперь мы можем добавить края:
for p in l:
for from_p in froms[p[1]]:
g.add_edge(p, from_p)
Далее две строки не нужны - они просто здесь, чтобы показать, как выглядит график на этом этапе:
>>> g.nodes()
[(25, 30), (14, 16), (10, 13), (8, 10), (1, 4), (19, 25)]
>>> g.edges()
[((8, 10), (10, 13)), ((19, 25), (25, 30))]
Теперь давайте разберёмся пары по топологической сортировки:
l = nx.topological_sort(g)
Наконец, вот сложная часть. Результатом будет DAG. Мы должны проходить рекурсивно, но помните, что мы уже посетили.
Давайте создадим Dict, что мы посетили:
visited = {p: False for p in l}
Теперь рекурсивная функция, что данный узел, возвращает максимальное преимущество в диапазоне от любого узла достижимый от него:
def visit(p):
neighbs = g.neighbors(p)
if visited[p] or not neighbs:
visited[p] = True
return p[1]
mx = max([visit(neighb_p) for neighb_p in neighbs])
visited[p] = True
return mx
Мы Все готово. Давайте создадим список для конечных пар:
final_l = []
и посетить все узлы:
for p in l:
if visited[p]:
continue
final_l.append((p[0], visit(p)))
Вот конечный результат:
>>> final_l
[(1, 4), (8, 13), (14, 16)]
Возможно ли иметь такой список, как '[(1, 4), (4, 8), (8, 10)]'? – skovorodkin
Вот краткая и грязная идея. Настройте два индекса для циклов со вторым запуском for-loop из индекса внешнего цикла. Проверьте, можете ли вы объединить кортежи, используя индекс из внешнего цикла, с индексом внутреннего цикла. Если вы можете заменить index [i] на '(a, d)' и повторить. – SuperSaiyan
Правильно, какой должен быть правильный способ справиться с этим –