如何创建一个功能sublist()
,其中包含两个列表list1
和list2
,如果True
是list1
的子列表,则返回list2
1}}和False
否则。如果list1
中的数字list2
中的数字与list1
中出现的数字相同,则list2
是list1
的子列表,但不一定是连续的。例如,
>>> sublist([1, 12, 3],[25, 1, 30, 12, 3, 40])
True
>>> sublist([5, 90, 2],[90, 20, 5, 2, 17])
False
答案 0 :(得分:8)
这是使用迭代器在线性时间(和常量空间)中进行此操作的一种方法:
def sublist(a, b):
seq = iter(b)
try:
for x in a:
while next(seq) != x: pass
else:
return True
except StopIteration:
pass
return False
基本上,它遍历子列表的每个元素,并查看它是否可以在完整列表的部分中找到它尚未查看的相同元素。如果它通过整个子列表,则意味着我们有一个匹配(因此for循环中的else语句)。如果我们在完整列表中看不到元素,那就意味着我们没有匹配。
编辑:我已更新我的解决方案,因此适用于Python 3.对于Python 2.5及更早版本,next(seq)
需要替换为seq.next()
。
答案 1 :(得分:5)
一个非常粗略的解决方案:
def sublist(a, b):
if not a:
return True
for k in range(len(b)):
if a[0] == b[k]:
return sublist(a[1:], b[k+1:])
return False
print sublist([1, 12, 3], [25, 1, 30, 12, 3, 40]) # True
print sublist([12, 1, 3], [25, 1, 30, 12, 3, 40]) # False
编辑:加速升级
答案 2 :(得分:2)
这是一个简化版本:
def sublist(a,b):
try:
return a[0] in b and sublist(a[1:],b[1+b.index(a[0]):])
except IndexError:
return True
>>> print sublist([1, 12, 3],[25, 1, 30, 12, 3, 40])
True
>>> print sublist([5, 90, 2],[90, 20, 5, 2, 17])
False
答案 3 :(得分:2)
这是一个迭代解决方案,应具有最优渐近:
def sublist(x, y):
if x and not y:
return False
i, lim = 0, len(y)
for e in x:
while e != y[i]:
i += 1
if i == lim:
return False
i += 1
return True
编辑:@ hetman的解决方案基本上具有相同的逻辑,但更多的是Pythonic,尽管与我的预期相反,它似乎稍微慢了一些。 (我对@ sshashan124解决方案的性能也不正确;递归调用的开销似乎超过了在C中做更多工作的好处。)
答案 4 :(得分:2)
祝贺一个看似棘手的问题。我认为这样可行但如果我错过了一个角落案例,特别是重复的元素,我不会感到震惊。受Hgu Nguyen递归解决方案启发的修订版本:
def sublist(a, b):
index_a = 0
index_b = 0
len_a = len(a)
len_b = len(b)
while index_a < len_a and index_b < len_b:
if a[index_a] == b[index_b]:
index_a += 1
index_b += 1
else:
index_b += 1
return index_a == len_a
一些粗略的分析:
鉴于需要遍历大部分或全部b
的列表,我的算法会受到影响:
a = [1, 3, 999999]
b = list(range(1000000))
在我的电脑上,Huu Nguyen或Hetman的算法大约需要10秒才能完成100次迭代检查。我的算法需要20秒。
鉴于早先的成功,Huu的算法大大落后于:
a = [1, 3, 5]
Hetman的算法或者我的算法可以在一秒钟内完成100k的检查 - 在我的PC上以0.13秒的速度完成Hetman,在0.19秒内完成。 Huu需要16秒才能完成1k的检查。我坦率地对这种程度的差异感到震惊 - 如果没有编译器优化,递归可能会很慢,我知道,但是4个数量级比我预期的要差。
给定一个失败列表a
,性能回到我需要遍历整个第二个列表时所看到的 - 可以理解,因为没有办法知道最后会有一个序列匹配其他无法匹敌的列表。
a = [3, 1, 5]
再次,Huu Nguyen或Hetman的100次测试算法大约10秒,我的20次。
更长的有序列表保持了我看到的早期成功模式。 EG:
a = range(0, 1000, 20)
Hetman的算法花费10.99秒完成100k测试,而我的算法花了24.08。 Huu用28.88完成了100次测试。
这些都不是你可以运行的全部测试,但在所有情况下,Hetman的算法表现最佳。
答案 5 :(得分:1)
这个怎么样:让我们从另一边接近这个:
def sublist(a,b):
"""returns True if a is contained in b and in the same order"""
return a == [ch for ch in b if ch in a]
在某些情况下这会失败(例如,[1,2,3]
应该是[1,1,8,2,3]
的一个子集),但很难确切地说出你希望如何实现这个...
答案 6 :(得分:1)
对于运行缓慢的快速解决方案,但对于您显示的大小的数组来说,它将完全足够:
def sublist(a,b):
last = 0
for el_a in a:
if el_a in b[last:]:
last = b[last:].index(el_a)
else:
return False
return True
**编辑为非连续元素工作
答案 7 :(得分:1)
这是另一种解决方案,新手可能比Hetman's更容易理解。 (请注意,它与this duplicate question中OP的实施非常接近,但避免了每次从b
开始重新启动搜索的问题。)
def sublist(a, b):
i = -1
try:
for e in a:
i = b.index(e, i+1)
except ValueError:
return False
else:
return True
当然,这需要b
为list
,而Hetman的回答允许任何可迭代。而且我认为(对于那些理解Python的人来说)它也不如Hetman的答案那么简单。
在算法上,它与Hetman的答案做同样的事情,所以它的O(N)时间和O(1)空间。但实际上,可能更快,至少在CPython中,因为我们将内循环从迭代器周围的Python while
移动到C fast-getindex循环(里面) list.index
)。然后,它可能会更慢,因为我们正在复制i
值而不是将所有状态嵌入(C实现的)迭代器中。如果重要,请使用您的实际数据对它们进行测试。 :)
答案 8 :(得分:0)
这是使用regex
的更好解决方案:
import re
def exiSt(short,long):
r = ''.join(["(.*"+str[x]+")" for x in short])
return re.match(r,','.join([str(x) for x in long])) == None
long = [1, 2, 3, 4, 5]
short1 = [1,2,5]
short2 = [1,5,3]
exiSt(short1,long)
>> True
exiSt(short2,long)
>> False
答案 9 :(得分:0)
def sublist(a, b):
"if set_a is not subset of set_b then obvious answer is False"
if not set(a).issubset(set(b)):
return False
n = 0
for i in a:
if i in b[n:]:
"+1 is needed to skip consecutive duplicates, i.e. sublist([2,1,1],[2,1]) = False"
"if +1 is absent then sublist([2,1,1],[2,1]) = True"
"choose to use or not to use +1 according to your needs"
n += b[n:].index(i) + 1
else:
return False
return True