Check if two items are in a list, in a particular

2020-02-09 14:43发布

Say I have a list v = [1, 2, 3, 4, 3, 1, 2]. I want to write a function, find_pair which will check if two numbers are in the list and adjacent to each other. So, find_pair(v, 2, 3) should return True, but find_pair(v, 1, 4) should return False.

Is it possible to implement find_pair without a loop?

标签: python list
13条回答
乱世女痞
2楼-- · 2020-02-09 15:10

If you are looking for a function that returns True or False depending on whether the two elements are consecutive or not irrespective of their orders then use this:

def find_pair(list, x, y):
    if abs(list.index(x)-list.index(y)) == 1:
        print(True)
    else:
        print(False)

But if the order of the elements are important then remove the abs() function inside the if condition. UPDATE:

A more robust one could be(if y is expected to follow x):

def find_pair(list, x, y):
if list[list.index(x)+1] == y:
    print(True)
else:
    print(False)
查看更多
▲ chillily
3楼-- · 2020-02-09 15:11

You're going to need a loop.

Unlike Python strings which support a subsequence test using the in operator, Python lists do not have a builtin subsequence test.

查看更多
我只想做你的唯一
4楼-- · 2020-02-09 15:14

Combining a few ideas here, these both seem to do the trick and are very fast

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

The simpler InList version is only slightly slower than @abhijit's solution while doing one less test, but still almost twice as fast as the top solution. The FasterInList version is about 25% faster than InList.

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
查看更多
\"骚年 ilove
5楼-- · 2020-02-09 15:16

I know you are already happy with one of the answer's in this post but, you may try with the following

>>> 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

Ok Curiosity got better of me and so wanted to test how does this implementation performed with the fastest posted implementation

>>> 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
>>> 

Gosh this is way fast

Note** Thanks Michael for pointing it out. I have corrected it and here is my updated solution.

查看更多
唯我独甜
6楼-- · 2020-02-09 15:17

Perhaps even simpler:

a = range(100)
exists = (55,56) in zip(a, a[1:])
查看更多
Summer. ? 凉城
7楼-- · 2020-02-09 15:29

This is probably a bit of a round about way to do it, but you could use (with your variable v above):

' 2, 3' in str(v)
查看更多
登录 后发表回答