Test whether list A is contained in list B
Asked Answered
R

8

8

I have two lists, A & B, and I would like to test whether A is contained in B. By "contained" I mean that the elements of A appear in the exact same order within B with no other elements between them. What I'm looking for is very similar to the behavior of A in B if they were strings.

Some elements of A will be repeated. We can assume A will be shorter than B.

There are many answers to similar questions on SO, but most answer a different question:

  • Is A an element of B? (Not my question: B is a flat list, not a list of lists.)
  • Are all the elements of A contained in B? (Not my question: I'm concerned about order as well.)
  • Is A a sublist of B? (Not my question: I don't want to know whether the elements of A appear in the same order in B, I want to know if they appear exactly as they are somewhere in B.)

If the operation were implemented as the keyword containedin, it would behave like this.

>>> [2, 3, 4] containedin [1, 2, 3, 4, 5]
True
>>> [2, 3, 4] containedin [1, 1, 2, 2, 3, 3, 4, 4, 5, 5]
False
>>> [2, 3, 4] containedin [5, 4, 3, 2, 1]
False
>>> [2, 2, 2] containedin [1, 2, 3, 4, 5]
False
>>> [2, 2, 2] containedin [1, 1, 2, 2, 3, 3, 4, 4, 5, 5]
False
>>> [2, 2, 2] containedin [1, 1, 1, 2, 2, 2, 3, 3, 3]
True

Is there a concise way to perform this operation in Python? Am I missing some important terminology that would have led me to the answer more quickly?

Rossner answered 19/1, 2019 at 15:0 Comment(8)
will the first list always be of length 3Hutch
@TalhaIsrar No. Clarified the text.Rossner
are the elements in the list always unique?Bogie
@Bogie No. Clarified the text again. :-)Rossner
i have left an easy ans hope it worksHutch
Um...someone want to explain their downvote? I put a lot of time into making it a clear question, and responding to requests for clarification.Rossner
but u have 4 upvotes?Hutch
Yeah, I'm not too worried. Just bugged me a bit since it was the second vote.Rossner
B
4

Use any with list slicing:

def contained_in(lst, sub):
    n = len(sub)
    return any(sub == lst[i:i+n] for i in range(len(lst)-n+1))

Or, use join to join both lists to strings and use in operator:

def contained_in(lst, sub):
    return ','.join(map(str, sub)) in ','.join(map(str, lst))

Usage:

>>> contained_in([1, 2, 3, 4, 5], [2, 3, 4])
True
>>> contained_in([1, 2, 2, 4, 5], [2, 3, 4])
False
Browband answered 19/1, 2019 at 15:7 Comment(1)
I have a love/hate relationship with that second suggestion. It's the hackiest, but in my opinion the clearest in terms of intent & syntax, and very concise. +1Rossner
S
3

many people have posted their answers. but I want to post my efforts anyway ;) this is my code:

def containedin(a,b):
    for j in range(len(b)-len(a)+1):
        if a==b[j:j+len(a)]:
            return True
    return False

print(containedin([2, 3, 4],[1, 2, 3, 4, 5]))
print(containedin([2, 3, 4],[1, 1, 2, 2, 3, 3, 4, 4, 5, 5]))
print(containedin([2, 3, 4],[5, 4, 3, 2, 1]))
print(containedin([2, 2, 2],[1, 2, 3, 4, 5]))
print(containedin([2, 2, 2],[1, 1, 1, 2, 2, 2, 3, 3, 3]))

this is the output: True False False False True

Sweetsop answered 19/1, 2019 at 15:22 Comment(0)
V
2

Assuming a always shorter than b what you can do is as follows.

 any(a == b[i:i+len(a)] for i in range(len(b)-len(a)+1))
Villasenor answered 19/1, 2019 at 15:7 Comment(0)
B
1

Considering you need to preserve order:

def contains(sub_array, array):
    for i in range(len(array)-len(sub_array)+1):
        for j in range(len(sub_array)):
            if array[i+j] != sub_array[j]:
                break
        else:
            return i, i+len(sub_array)
    return False
Bogie answered 19/1, 2019 at 15:11 Comment(1)
Nice. Even gives you the index of the first occurrence.Rossner
H
0

Use this function

I tried to not make it complex

def contains(list1,list2):

    str1=""
    for i in list1:
        str1+=str(i)

    str2=""
    for j in list2:
        str2+=str(j)

    if str1 in str2:
        return True

    else:
        return False

Hope it works :)

Hutch answered 19/1, 2019 at 15:11 Comment(0)
D
0

You can concatenate the 2 lists into two different strings. Then, write a function to check if one string is in another.

def containedin(a, b):
 if b in a:
  return True
 return False`
Dashpot answered 19/1, 2019 at 15:13 Comment(0)
T
0

Something like this?

class myList(list):
    def in_other(self, other_list):
        for i in range(0, len(other_list)-len(self)):
            if other_list[i:i+len(self)] == self:
                return True
            else:
                continue

if __name__ == "__main__":

    x = myList([1, 2, 3])
    b = [0, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6]

    print(x.in_other(b))
Tivoli answered 19/1, 2019 at 15:16 Comment(0)
P
0

No need to slice for every element:

def contains(seq, sub):
    sub_length = len(sub)
    sub_first = sub[0]
    return any(sub == seq[index:index+sub_length]
               for index, element in enumerate(seq)
               if element == sub_first)

Usage:

>>> seq = [1, 2, 3, 4, 5]
>>> sub = [2, 3, 4]

>>> contains(seq, sub)
True
Pedagogy answered 19/1, 2019 at 15:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.