简体   繁体   中英

Python 3: check if the entire list is inside another list

Let's say I have 2 lists:
a = [6,7,8,9,10]
b = [1,3,4,6,7,8,9,10]

I have a function that is used to find out if list a can be found in list b . If it is found, then it returns True . In my case it should return True because list a can be found at the end of list b . List a never changes and always contains the same numbers, whereas list b accepts numbers from the user and then uses sorted() method to sort numbers in ascending order. I should also add that the order does matter.

I have searched around and could find a subset method, which looks like this: set(a).issubset(set(b))) as well as using in method. Both of them did not work for me.

UPDATE : Using set(a).issubset(set(b))) for some reason always returns True. For example, if a = [1,1] and b = [0,1,2,3,4,5] then using subset method returns True, even though 1,1 cannot be found in b. I'm not looking if 1 is inside the list, I'm looking if 1,1 is inside the list.

Using in method when
a = [6,7,8,9,10]
b = [1,3,4,6,7,8,9,10] returns False.

You didn't say how important speed was. So I'd wrap the functionality in a class, so that you can hide the complications from the rest of your code if you need to get fancier later. Since

List a never changes and always contains the same numbers

it makes sense to pass a to the class constructor. Here's one way:

class ASearcher:
    def __init__(self, a):
        self.a = a
    def isin(self, b):
        a = self.a
        a0 = a[0]
        lena = len(a)
        i = 0
        try:
            while 1:
                j = b.index(a0, i) # raises ValueError if not found
                if a == b[j: j+lena]:
                    return True
                i = j+1  # start search over 1 position later
        except ValueError:
            return False

Then, eg,

asearch = ASearcher([6,7,8,9,10])
print asearch.isin([1,3,4,6,7,8,9,10])

prints True .

There is no function in the standard library to do what you want here, so you need to roll your own. The class above implements a method that does the searching, in B, for the first element of A, "at C speed". It will probably be "fast enough" - maybe ;-)

If the values in a and b happen to be in the range 0-255, you can use this trick

>>> a = [6,7,8,9,10]
>>> b = [1,3,4,6,7,8,9,10]
>>> bytearray(a) in bytearray(b)
True

Here is a brute force way:

a = [6,7,8,9,10]
b = [1,3,4,6,7,8,9,10]

def check_if_in_list(a, b):
    for i in xrange(len(b) - len(a) + 1):
        if a == b[i : i + len(a)]:
            return True
    return False

Result:

>>> check_if_in_list(a, b)
True

If I understand you, you're interested in knowing whether a is a contiguous subsequence of b . So:

>>> a = [6,7,8,9,10]
>>> b = [1,3,4,6,7,8,9,10]
>>> any(b[i:i+len(a)] == a for i in range(len(b)-len(a)+1))
True

This isn't the most efficient approach, but it'll often be fast enough in practice.

Something you find useful

idx = -1
notfound = False
for index, item in enumerate(b):
    if item == a[0]:
        idx = index
if idx == -1:
    notfound = True
for i in xrange(idx, len(a) + idx):
    if len(b) <= i or a[i - idx] != b[i]:
        notfound = True
print "Not found: ", notfound

You do not need to loop over each and every index. Just find the first element and then see of the remainder elements match.

You could do something along these lines:

a = [6,7,8,9,10]
b = [1,3,4,6,7,8,9,10]

def liAinliB(a, b):
    try:
        ind=b.index(a[0])
    except ValueError:
        return False

    return b[ind:ind+len(a)]==a

print(liAinliB(a, b))  

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM