说我有一个列表v = [1, 2, 3, 4, 3, 1, 2]
。我想编写一个函数find_pair
,它将检查列表中是否有两个数字并且彼此相邻。因此,find_pair(v, 2, 3)
应返回True
,但find_pair(v, 1, 4)
应返回False
。
是否可以在没有循环的情况下实施find_pair
?
答案 0 :(得分:9)
v = [1,2,3,4,3,1,2]
any([2,3] == v[i:i+2] for i in xrange(len(v) - 1))
虽然@ PaoloCapriotti的版本可以解决问题,但这个版本更快,因为只要找到匹配就会停止解析v
。
答案 1 :(得分:3)
[2, 3] in [v[i:i+2] for i in range(len(v) - 1)]
答案 2 :(得分:3)
这可能是一个很好的方法,但你可以使用(上面你的变量v):
' 2, 3' in str(v)
答案 3 :(得分:2)
v = [1,2,3,4,3,1,2]
def find(x,y,v):
return (x,y) in zip(v,v[1:])
print find(2,3,v)
print find(1,4,v)
答案 4 :(得分:2)
或许更简单:
a = range(100)
exists = (55,56) in zip(a, a[1:])
答案 5 :(得分:1)
一般来说,如果不迭代所有值,就不可能。毕竟,一千个元素的列表可能会以[.., 2, 3]
结尾。
在特殊情况下,有快捷方式。这些值是否始终排序,您是否始终在寻找特定值?如果是这样,您可以例如使用二进制搜索来查找值,然后将其与下一个值进行比较。如果值无序,则没有快捷方式。如果您要查找任何两个后续值,则没有快捷方式。对于介于两者之间的案例,可能会有一条捷径。
答案 6 :(得分:1)
你需要一个循环。
与使用 in 运算符支持子序列测试的Python字符串不同,Python列表没有内置子序列测试。
答案 7 :(得分:1)
您可以使用Boyer-Moore algorithm进行完全不必要的加速。一般情况有点困难,但如果您只是寻找一对,那就很简单了。
def find_pair(seq, a, b):
i = 1
while i < len(seq):
if seq[i] == b and seq[i - 1] == a: return i - 1
i += 2 - (seq[i] == a)
print find_pair([1, 5, 3, 4, 3, 1, 2, 3, 3], 2, 3)
答案 8 :(得分:0)
如果编写列表的次数远远少于读取列表,那么也许你可以在写入时构建一个前缀树。 [1]会有一个子节点[2],[2]会有[3]和[3] a [4]。使用更复杂的数据集,树将更有用。在您的情况下,它的深度为2,并将在搜索序列中的初始元素上编入索引。
您仍然要访问每个节点,但只搜索序列的生命周期一次,如果仅追加。当您追加元素时,您将更新树以包括子序列(如果不存在)。然后读取最多为O(2 * k),其中k是唯一元素的数量。在数字的情况下,20是最大值,以测试序列是否在列表中。
速度优势来自预先计算列表包含的长度为2的子序列以及删除重复项。它也可以很好地扩展到更长的长度。 O(深度* k)最坏的情况。如果使用哈希表,那就更好了。
答案 9 :(得分:0)
我知道你已经对这篇文章中的一个答案感到满意了,但你可以试试以下
>>> v = [1,2,3,4,3,1,2]
def InList(v,(i,j)):
start=1
try:
while True:
if v[v.index(i,start)+1]==j and v[v.index(j,start)-1]==i:
return True
start=v.index(i)+1
except IndexError:
return False
except ValueError:
return False
>>> InList(v,(2,3))
True
>>> InList(v,(4,5))
False
>>> InList(v,(1,2))
True
>>> InList(v,(12,2))
False
>>> InList(v,(3,1))
True
好的好奇心让我变得更好,所以想要测试这个实现如何通过最快发布的实现来执行
>>> stmt1="""
v = [1,2,3,4,3,1,2]
def InList(v,(i,j)):
start=1
try:
while True:
if v[v.index(i,start)+1]==j and v[v.index(j,start)-1]==i:
return True
start=v.index(i)+1
except IndexError:
return False
except ValueError:
return False
InList(v,(2,3))
InList(v,(4,5))
InList(v,(1,2))
InList(v,(12,2))
"""
>>> stmt2="""
v = [1,2,3,4,3,1,2]
def InList(v,(x,y)):
any([x,y] == v[i:i+2] for i in xrange(len(v) - 1))
InList(v,(2,3))
InList(v,(4,5))
InList(v,(1,2))
InList(v,(12,2))
"""
>>> t1=timeit.Timer(stmt=stmt1)
>>> t2=timeit.Timer(stmt=stmt2)
>>> print "%.2f usec/pass" % (1000000 * t1.timeit(number=100000)/100000)
13.67 usec/pass
>>> print "%.2f usec/pass" % (1000000 * t2.timeit(number=100000)/100000)
20.67 usec/pass
>>>
天哪,这很快
注意**感谢Michael指出。我已经更正了,这是我更新的解决方案。
答案 10 :(得分:0)
list.index()
方法,这样可以节省一些时间来迭代整个列表。
v = [1,2,3,4,3,1,2]
def f1(items):
return any([2,3] == v[i:i+2] for i in xrange(len(v) - 1))
def f2(items):
i = 0
index = items.index
try:
while 1:
i = index(2, i) + 1
if items[i] == 3:
return True
except IndexError:
return False
from timeit import repeat
print "f1", min(repeat("f1(v)", "from __main__ import f1, v", number=1000))
print "f2", min(repeat("f2(v)", "from __main__ import f2, v", number=1000))
当我跑步时,我得到:
f1 0.00300002098083
f2 0.0
当匹配不是如此接近列表的开头时,这应该更快。
答案 11 :(得分:0)
如果您要寻找一个根据两个元素是否连续而不论其顺序如何而返回True或False的函数,请使用以下方法:
def find_pair(list, x, y):
if abs(list.index(x)-list.index(y)) == 1:
print(True)
else:
print(False)
但是,如果元素的顺序很重要,则在if条件中删除abs()函数。 更新:
可能会更健壮(如果y预期跟随x):
def find_pair(list, x, y):
if list[list.index(x)+1] == y:
print(True)
else:
print(False)
答案 12 :(得分:0)
结合这里的一些想法,它们似乎都可以解决问题,而且非常快
def InList(v, (x, y)):
return any((x == v[i] and y == v[i + 1]) for i in xrange(len(v) - 1))
def FasterInList(v, (x, y)):
if x in v:
indices = [i for i, match in enumerate(v) if match == x]
for i in indices:
if v[i+1] == y:
return True
return False
更简单的InList版本仅比@abhijit的解决方案稍慢一点,同时减少了一次测试,但仍几乎是顶级解决方案的两倍。 FasterInList版本比InList快25%。
import timeit
abhijit = """
v = [1,2,3,4,3,1,2]
def abhijit(v,(i,j)):
start=1
try:
while True:
if v[v.index(i,start)+1]==j and v[v.index(j,start)-1]==i:
return True
start=v.index(i)+1
except IndexError:
return False
except ValueError:
return False
abhijit(v,(2,3))
abhijit(v,(4,5))
abhijit(v,(1,2))
abhijit(v,(12,2))
"""
# abhijit(v,(3,2)) this never breaks out of the while loop
top = """
v = [1,2,3,4,3,1,2]
def top(v,(x,y)):
any([x,y] == v[i:i+2] for i in xrange(len(v) - 1))
top(v,(2,3))
top(v,(4,5))
top(v,(1,2))
top(v,(12,2))
top(v,(3,2))
"""
InList = """
v = [1,2,3,4,3,1,2]
def InList(v, (x, y)):
return any((x == v[i] and y == v[i + 1]) for i in xrange(len(v) - 1))
InList(v,(2,3))
InList(v,(4,5))
InList(v,(1,2))
InList(v,(12,2))
InList(v,(3,2))
"""
FasterInList = """
v = [1,2,3,4,3,1,2]
def FasterInList(v, (x, y)):
if x in v:
indices = [i for i, match in enumerate(v) if match == x]
for i in indices:
if v[i + 1] == y:
return True
return False
FasterInList(v,(2,3))
FasterInList(v,(4,5))
FasterInList(v,(1,2))
FasterInList(v,(12,2))
FasterInList(v,(3,2))
"""
top_timer = timeit.Timer(stmt=top)
abhijit_timer = timeit.Timer(stmt=abhijit)
InList_timer = timeit.Timer(stmt=InList)
FasterInList_timer = timeit.Timer(stmt=FasterInList)
print "%.2f usec/pass" % (1000000 * top_timer.timeit(number=100000)/100000) # 8.79 usec/pass
print "%.2f usec/pass" % (1000000 * abhijit_timer.timeit(number=100000)/100000) # 4.42 usec/pass
print "%.2f usec/pass" % (1000000 * InList_timer.timeit(number=100000)/100000) # 4.66 usec/pass
print "%.2f usec/pass" % (1000000 * FasterInList_timer.timeit(number=100000)/100000) # 3.70 usec/pass