簡體   English   中英

在列表列表中組合至少具有共同數字的列表,Python

[英]Combine lists that have at least a number in common in a list of lists, Python

考慮這個列表列表:

l = [ [1], [1], [1,2,3], [4,1], [5], [5], [6], [7,8,9], [7,6], [8,5] ]

我希望將所有具有至少一個共同數字的列表組合在一起,這將是迭代完成的,直到完成並且不會有任何二重奏。 結果將是:

combine(l) = [ [1,2,3,4], [5,6,7,8,9] ]

有沒有任何巧妙的方法來做到這一點,也許與itertools?

out = []
for l in lists:
    for o in out:
        if set(l).intersection(set(o)):
            o[:] = list(set(l) + set(o))  # Mutate, don't reassign temp var
            break
    else:
        out.append(l)

沒有寫得很完美,可以進行優化並且不進行排序,但應該讓您了解如何進行操作。

也許這個?

l = [ [1], [1], [1,2,3], [4,1], [5], [5], [6], [7,8,9], [7,6], [8,5] ]
a, b = [], map(set, l)

while len(a) != len(b):
    a, b = b, []
    for x in a:
        for i, p in enumerate(b):
            if p & x:
                b[i] = p | x
                break
        else:
            b.append(x)        

print a
# [set([1, 2, 3, 4]), set([5, 6, 7, 8, 9])]

我天真的嘗試:

  1. 當交集不為空時合並所有元組
  2. 排序每個元組
  3. 刪除重復的元組
  4. 重復此操作,直到沒有更多更改。

例:

def combine_helper(l):
    l = map(set, l)
    for i, x in enumerate(l, 1):
        x = set(x)
        for y in l[i:]:
            if x & y:
                x = x | y
        yield tuple(sorted(x))

def combine(l):
    last_l = []
    new_l = l
    while last_l != new_l:
        last_l = new_l
        new_l = list(set(combine_helper(last_l)))
    return map(list, last_l)

l = [ [1], [1], [1,2,3], [4,1], [5], [5], [6], [7,8,9], [7,6], [8,5] ]
print combine(l)

輸出:

$ python test.py
[[1, 2, 3, 4], [5, 6, 7, 8, 9]]

救援的遞歸! 不要忘記減少!

input_list = [ [1], [1], [1, 2, 3], [4, 1], [5], [5], [6], [7, 8, 9], 
               [7, 6], [8, 5] ]
def combine(input_list):
    input_list = map(set, input_list) # working with sets has some advantages
    reduced_list = reduce(combine_reduce, input_list, [])
    if len(reduced_list) == len(input_list):
        # return the whole thing in the original format (sorted lists)
        return map(sorted, map(list, reduced_list))
    else:
        # recursion happens here
        return combine(reduced_list)

def combine_reduce(reduced_list, numbers):
    '''
    find the set to add the numbers to or append as a new set.
    '''
    for sub_set in reduced_list:
        if sub_set.intersection(numbers):
            sub_set.update(numbers)
            return reduced_list
    reduced_list.append(numbers)
    return reduced_list

print combine(input_list)

打印出來:

$ python combine.py
[[1, 2, 3, 4], [5, 6, 7, 8, 9]]

我們這里有兩件事。 第一個是reduce :我正在使用它來制作列表,通過將每個元素放入某個結果列表或附加它,如果這不起作用。 但是,這並不能完成整個工作,所以我們重復這個過程(遞歸!),直到reduce不提供更短的列表。

此外,使用set允許方便的intersection方法。 您會注意到帶有map(set, input_list)遞歸時是多余的。 從內部函數combine_inner提取包裝函數combine ,並將外部函數中的格式化/ combine_inner格式化(從list set和返回)放置為練習。

有可能引入以下嘗試:

  1. 列出包含列表中各個值的1元素集。 這是輸出列表。
  2. l列表是一個配方,應該如何連接輸出列表中的項目。 例如,如果輸出列表是[{1}, {2}, {3}]並且l列表中的第一個元素是[1,3] ,那么輸出列表中包含1和3的所有集合都應該連接: output = [{1,3}, {2}]
  3. 對l列表中的每個項重復步驟2。

碼:

l = [ [1], [1], [1,2,3], [4,1], [5], [5], [6], [7,8,9], [7,6], [8,5] ]

def compose(l):
    # the following will convert l into a list of 1-element sets:
    # e.g. [ {1}, {2}, ... ]
    r = sum(l, [])
    r = map(lambda x: set([x]), set(r))

    # for every item in l
    # find matching sets in r and join them together
    for item in map(set, l):
        outside = [x for x in r if not x & item]  # elements untouched
        inside = [x for x in r if x & item]       # elements to join
        inside = set([]).union(*inside)           # compose sets 
        r = outside + [inside]
    return r

例:

>>> compose(l)
[set([1, 2, 3, 4]), set([8, 9, 5, 6, 7])]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM