我知道这个问题看起来像是重复的。但我很难解决这个问题,而且我找不到有用的解决方案
我正在使用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。
换句话说:我希望看到这些列表之间的共同路径。
如果有任何不清楚的地方,请告诉我 提前致谢。
答案 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上:
答案 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)
你可以尝试利用它来获得位置交叉点。