LaDuelo
LaDuelo

Reputation: 51

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.

Upvotes: 0

Views: 637

Answers (6)

dawg
dawg

Reputation: 103844

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

Upvotes: 0

John La Rooy
John La Rooy

Reputation: 304175

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

Upvotes: 1

evhen14
evhen14

Reputation: 1927

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

Upvotes: 0

Tim Peters
Tim Peters

Reputation: 70602

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, e.g.,

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

Upvotes: 2

DSM
DSM

Reputation: 353059

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.

Upvotes: 0

Akavall
Akavall

Reputation: 86188

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

Upvotes: 0

Related Questions