Мне нужно сгруппировать подсписки с одинаковыми элементами. Например:

list1 =[[1, 0], [2, 1], [30, 32]]

Свяжет [1, 0] и [2, 1] вместе, поскольку они оба содержат 1, и эти два объединятся в [0, 1, 2]

Поэтому после ссылки новый список должен выглядеть так:

new_list1 = [[1, 0, 2], [30, 32]]

IE: внутри подсписка не должно быть одинакового номера, и порядок не важен.

Более длинный пример:

list2 = [[2, 3], [4, 3], [6, 5], [7, 6], [7, 8], [13, 14], [30, 32]]

После ссылки было бы

new_list2 = [[2, 3, 4], [6, 5, 7, 8], [13, 14], [30, 32]]

Итак, как это можно сделать в целом?

-2
Ch Y Duan 28 Май 2017 в 02:27

2 ответа

Лучший ответ

Чтобы сгруппировать списки в общем виде, вы можете:

Код:

def linking_sublists(lists):
    index = {}
    sets = []
    for l in lists:
        found = None
        for i in l:
            if i in index:
                # this list has an element we have already seen
                if found:
                    # combine two sets
                    to_remove = index[i]
                    if found != to_remove:
                        for j in index[i]:
                            found.add(j)
                            index[j] = found
                        to_remove.clear()
                else:
                    found = index[i]

        if found is not None:
            s = found
            for i in l:
                s.add(i)
        else:
            s = set(l)
            sets.append(s)
        for i in l:
            index[i] = s

    return [list(sorted(s)) for s in sets if s]

Как:

Эта функция использует группы и индекс dict для группировки любой список с соответствующими элементами в наборы и отслеживать, какие элементы уже есть в {{X1 } }.

Тестовый код:

list_2 = [[2, 3], [4, 3], [6, 5], [7, 6], [7, 8], [13, 14], [30, 32]]
print(linking_sublists(list_2))

list_3 = [[2, 3], [4, 3], [6, 5], [7, 6], [7, 8], [30, 32], [4, 5], [3, 4]]
print(linking_sublists(list_3))

Результаты:

[[2, 3, 4], [5, 6, 7, 8], [13, 14], [30, 32]]
[[2, 3, 4, 5, 6, 7, 8], [30, 32]]
2
Stephen Rauch 28 Май 2017 в 01:35

Одним из способов решения этой проблемы является представление каждого подсписка как узла в графе. Два узла имеют общее ребро, если они имеют общие элементы.

Острова («связанные компоненты» или просто «компоненты») графика могут затем использовать для создания новых списков. График для list2 будет выглядеть так:

[2,3]<--->[4,3]

[6,5]<--->[7,6]<--->[7,8]

[13,14]   [30,32]

Эскиз кода (не проверено):

list2=[[2,3],[4,3],[6,5],[7,6],[7,8],[13,14],[30,32]]

# Convert to tuples for easier handling
l2 = [tuple(item) for item in list2]

# Build a graph
graph = {item: set() for item in l2}
for sublist in l2:
    for sublist2 in l2:
        if sublist == sublist2:
            continue
        for item in sublist:
            if item in sublist2:
                graph[sublist].add(sublist2)

# Find all nodes that start_node is connected to
def island(graph, start_node):
    visited = set()
    visited.add(start_node)
    frontier = set(graph[start_node])
    while frontier:
        node = frontier.pop()
        visited.add(node)
        frontier.update(n for n in graph[node] if n not in visited)
    return visited

# Find all islands
islands = []
for sublist in l2:
    i = island(graph, sublist)
    if i not in islands:
        islands.append(i)

# Build the new lists by getting all unique numbers from each island
[list(set(item for sublist in island for item in sublist)) for island in islands]

# Output:
# [[2, 3, 4], [8, 5, 6, 7], [13, 14], [32, 30]]

Вышесказанное может быть улучшено, и способ построения графика, и способ нахождения компонентов можно сделать более эффективными.

Такое мышление может быть использовано для решения множества различных проблем. Тем не менее, мне больше нравится решение Стивена Рауха из-за его простоты.

1
André Laszlo 28 Май 2017 в 00:39