如何在python中相对于索引交叉列表

时间:2012-06-08 00:05:31

标签: python list

我知道这个问题看起来像是重复的。但我很难解决这个问题,而且我找不到有用的解决方案

我正在使用python实现旅行商问题的遗传算法

假设我们有这些列表(游览)

a = [1,0,2,5,4,3,1]
b = [1,2,5,4,3,0,1]
c = [1,3,5,4,2,0,1]

如您所见,[5,4]在整个3个列表中重复出现 并且常规交叉点将返回列表中的所有元素。

我想要一些像intersect_list(a,b)

这样的函数

返回[5,4]

有没有python内置的方法来找到它?或者你有什么建议吗?。

注意:我知道我可以循环来解决这个问题,但请记住,在我的情况下,我有大约400个列表。并且每个长度为401。

换句话说:我希望看到这些列表之间的共同路径。

如果有任何不清楚的地方,请告诉我 提前致谢。

4 个答案:

答案 0 :(得分:3)

在看了@pyfunc发布的链接之后,我想出了以下内容:

def shortest_of(lists):
    return min(lists, key=len)

def contains_sublist(lst, sublst):
    n = len(sublst)
    return any((sublst == lst[i:i+n]) for i in xrange(len(lst)-n+1)) 

def longest_common(lists):
    if not lists:
        return ()
    res = set()    
    base = shortest_of(lists)
    length = len(base)

    for i in xrange(length, 0, -1):
        for j in xrange(length - i + 1):
            candidate = ', ' + str(base[j:i+j]).strip('[]') + ','
            #candidate = base[j:i+j]  

            for alist in lists:
                if not candidate in ', ' + str(alist).strip('[]') + ',':
                #if not contains_sublist(alist, candidate):   
                    break
            else:
                res.add(tuple([int(a) for a in candidate[2:-1].split(',')]))
                #res.add(tuple(candidate))

        if res:
            return tuple(res)    

    return ()

if __name__ == '__main__':
    a = [1,0,2,5,4,3,1]
    b = [1,2,5,4,3,0,1]
    c = [1,3,5,4,2,0,1]

    print longest_common([a,b,c])
    print longest_common([b,c])

输出:

((5, 4),)
((0, 1), (5, 4))

编辑:

更新了使用字符串转换和匹配的解决方案,因为它碰巧更快。以前的解决方案部分已被注释掉。此外,它现在提供了所有可能性。

答案 1 :(得分:1)

一个想法是,您可以将列表转换为带有

的字符串
",".join(list)

然后将问题转换为两个字符串中最长的匹配子字符串。

解决方案和讨论就在SO上:

  1. Longest common substring from more than two strings - Python
  2. http://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Longest_common_substring#Python

答案 2 :(得分:1)

400长度400的列表并不是太大的问题。首先将每个序列分成所有可能的子序列,(长度N的列表具有大约0.5 * N ** 2个可能的子序列。然后将它们全部交叉并取最长的一个。

a = [1,0,2,5,4,3,1]
b = [1,2,5,4,3,0,1]
c = [1,3,5,4,2,0,1]

def longest_match_finder(lists):
    matches = []
    for a in lists:
        lengths = set()
        for leng in xrange(1,len(a)+1):
            lengths = lengths | set(tuple(a[i:i+leng]) 
                                    for i in xrange(len(a)-leng+1))
        matches.append(lengths)
    return max(set.intersection(*matches), key=len)

print longest_match_finder([a,b,c])
#Output:
(5, 4)

400每个都列有400个元素,这需要280 seconds(在我很老的机器上)。但是,如果我们在一个列表中使用相同的方法,但是将其子序列以及所有其他列表转换为字符串(由@pyfunc首先发布),使用str(list).strip('[]'),我们可以更快地搜索。相同的测试在21 seconds

中运行
import ast

def longest_match_finder_2(lists):
    a = lists[0]
    lengths = set()
    for leng in xrange(1,len(a)+1):
        lengths = lengths | set(str(a[i:i+leng]).strip('[]') 
                                for i in xrange(len(a)-leng+1))
    for seq in lengths.copy():
        if not all([seq in str(i).strip('[]') for i in lists[1:]]):
            lengths.remove(seq)
    return ast.literal_eval(max(lengths, key=len))

我们可以使用ast.literal_eval()在最后(安全地)获取列表。

答案 3 :(得分:-1)

您可以使用列表zip函数将它们压缩为元组并返回所有元素相同的元组。

a = [1,0,2,5,4,3,1]
b = [1,2,5,4,3,0,1]
c = [1,3,5,4,2,0,1]
zipped_tuples = zip(a, b, c)

你可以尝试利用它来获得位置交叉点。