在列表列表中组合至少具有共同数字的列表,Python

时间:2013-05-06 13:48:11

标签: python list

考虑这个清单列表:

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?

5 个答案:

答案 0 :(得分:1)

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)

写得不完美,可以进行优化,也不会排序,但应该让您了解如何操作。

答案 1 :(得分:1)

也许这个?

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

答案 2 :(得分:0)

我天真的尝试:

  1. 在交叉点不为空时合并所有元组
  2. 对每个元组进行排序
  3. 删除重复的元组
  4. 重复此操作,直到没有更多更改。

  5. 示例:

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

答案 3 :(得分:0)

救援的递归!不要忘记减少!

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中提取包装函数combine_inner并在外部函数中放置格式化/取消格式化(从listset并返回)作为练习。

答案 4 :(得分:0)

可以引入以下尝试:

  1. 列出包含列表中各个值的1元素集。这是输出列表。
  2. l列表是一个配方,应该如何连接输出列表中的项目。例如如果输出列表为[{1}, {2}, {3}]且l列表中的第一个元素为[1,3],则输出列表中包含1和3的所有集合都应加入:output = [{1,3}, {2}]
  3. 对l列表中的每个项目重复步骤2.
  4. 代码:

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