检查列表中是否有两个项目按特定顺序排列?

时间:2011-12-24 15:28:25

标签: python list

说我有一个列表v = [1, 2, 3, 4, 3, 1, 2]。我想编写一个函数find_pair,它将检查列表中是否有两个数字并且彼此相邻。因此,find_pair(v, 2, 3)应返回True,但find_pair(v, 1, 4)应返回False

是否可以在没有循环的情况下实施find_pair

13 个答案:

答案 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)

eumiro的回答赢得了优雅,但如果你需要更快的东西,你可以利用内置的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