Python用交集合并多个列表

时间:2012-02-19 22:15:02

标签: python list intersection

  

可能重复:
  Python: simple list merging based on intersections

我有一个多个列表:

 list=[[1,2,3],[3,5,6],[8,9,10],[11,12,13]]

是否有一种智能且快速的方法来获得至少有一个交叉点的所有子列表。在我的例子中,我希望代码返回

 result=[[1,2,3,5,6],[8,9,10],[11,12,13]]

3 个答案:

答案 0 :(得分:0)

这样可行,但可能不是很优雅:

def merge_lists(l):
        s=map(set, l)
        i, n=0, len(s)
        while i < n-1:
                for j in xrange(i+1, n):
                        if s[i].intersection(s[j]):
                                s[i].update(s[j])
                                del s[j]
                                n-=1
                                break
                else:
                        i+=1
        return [sorted(i) for i in s]

答案 1 :(得分:0)

您只需一次通过数据即可完成此操作:

list_of_lists = [[1, 2, 3], [3, 5, 6], [8, 9, 10], [11, 12, 13]]
sets = {}
for lst in list_of_lists:
    s = set(lst)
    t = set()
    for x in s:
        if x in sets:
            t.update(sets[x])
        else:
            sets[x] = s
    for y in t:
        sets[y] = s
    s.update(t)
ids = set()
for s in sets.itervalues():
    if id(s) not in ids:
        ids.add(id(s))
        print s

这会创建一个字典sets,将每个元素映射到它所属的集合。如果之前已经看到某个元素,则其集合将包含在当前元素中,并且将更新映射到前一个集合的所有dictinary条目。

最后,我们需要在字典sets的值中找到所有唯一集。请注意,虽然我将其实现为集合字典,但代码也适用于列表而不是集合。

答案 2 :(得分:0)

好问题!如果您将其视为图中的连接组件问题,则会更简单。以下代码使用了出色的networkx图表库和this question中的pairs函数。

def pairs(lst):
    i = iter(lst)
    first = prev = item = i.next()
    for item in i:
        yield prev, item
        prev = item
    yield item, first

lists = [[1,2,3],[3,5,6],[8,9,10],[11,12,13]]

import networkx
g = networkx.Graph()
for sub_list in lists:
    for edge in pairs(sub_list):
            g.add_edge(*edge)

networkx.connected_components(g)
[[1, 2, 3, 5, 6], [8, 9, 10], [11, 12, 13]]

说明

我们创建一个新的(空)图g。对于lists中的每个子列表,将其元素视为图的节点,并在它们之间添加边。 (因为我们只关心连通性,所以我们不需要添加 all 边缘 - 只有相邻的边缘!)注意add_edge需要两个对象,将它们视为节点(并添加如果他们还没有在那里,他们就会增加他们之间的优势。

然后,我们只是找到图表的连接组件 - 一个已解决的问题! - 并将它们作为交叉集输出。