繁体   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