tags:

views:

248

answers:

10

I want to do this. I have two python lists, one larger than the other and I want to know is there is a way to check if the elements of the smaller list are in the big list in the exact same order for example:

small_list = [4,2,5]
big_list = [1,2,5,7,2,4,2,5,67,8,5,13,45]

I tried using the in keyword but It did not worked :'(

A: 

There's no built in operator doing that particular comparison. I suggest a list comprehension or a quick for loop.

Paul McMillan
+3  A: 

Rather non-optimized, demonstrates the general strategy simply:

tuple(small_list) in zip(big_list[:], big_list[1:], big_list[2:])

The funky zip thing does this:

>>> zip(big_list[:], big_list[1:], big_list[2:])
[(1, 2, 5), (2, 5, 7), (5, 7, 2), (7, 2, 4), (2, 4, 2), (4, 2, 5), (2, 5, 67), (5, 67, 8), (67, 8, 5), (8, 5, 13), (5, 13, 45)]

A more optimized version:

from itertools import izip, islice
tuple(small_list) in izip(big_list, islice(big_list, 1, None), islice(big_list, 2, None))

To handle small_list length of any size:

from itertools import izip, islice
tuple(small_list) in izip(*(islice(big_list, i, None) for i in xrange(len(small_list))))
ʞɔıu
Interesting solution. Not very general, but works ok if the small list is ALWAYS VERY SMALL.
Paul McMillan
generalizing it for different length of the small list is straightforward
ʞɔıu
Isn't this solution optimal even if small_list is not very small?
unutbu
the optimized versions using itertool's generator functions should be perfectly OK
ʞɔıu
+2  A: 

This problem is trickier than it seems. Unless I'm mistaken, it's a special case of the longest common substring problem.

For the general case (arbitrarily large lists), I would use some kind of finite state automaton, akin to a regular expression. I believe the result could then be calculated in O(mn) time.

Daniel Pryden
You are mistaken. It's the same as finding if a substring T in S, which is doable in linear time.
Andrew Dalke
@Daniel: It's the same as finding a substring, true. However IIRC that is worst case O(mn) e.g. T = "a" * 8 + "b"; S = "a" * 9 * 100 when done with brute force algorithms as presented in answers here.
John Machin
+2  A: 

That's because small_list in big_list checks whether an element in big_list is equal to small_list. What you want to do instead is see if a slice of big_list is the same as small_list.

def isSubList(slice, L):
    n = len(slice)
    for i in range(0, len(L) - n):
        if slice == L[i:i+n]:
            return True
    return False

isSubList(small_list, big_list)
jamessan
does not works :-(
Fitoria
Works fine here...
jamessan
+7  A: 
def in_list(small, big):
    l_sml = len(small)
    l_big = len(big)
    return any((big[i:i+l_sml]==small for i in xrange(l_big-l_sml+1)))

print in_list([4,2,1], [1,2,3,4,2,1,0,5]) # True
print in_list([1,2,3], [1,2,4])           # False
ChristopheD
this one works!
Fitoria
Maybe better to replace the `if True in` with the `any()` function?
Daniel Pryden
Splendid suggestion, thanks ! (I edited the answer accordingly). 'any' is one of those functions I tend to always forget about...
ChristopheD
And please make it 'return any(...)'. any() already returns a boolean.
unbeknown
Point taken ;-)
ChristopheD
+1  A: 

Edit: Leaving the answer here but I failed to note the requirement that they be in the same order. This does not meet that requirement

Quick and dirty answer. Based it off of the answer for Python - Intersection of two lists

small_list == filter( lambda x: x in big_list, small_list)
Jesse
I liked this answer :(
igorgue
this one is elegant :-)
Fitoria
A: 

you could use sets

from sets import Set
small_set = set(small_list)
big_set = set(big_list)
small_set <= big_set

<= is the subset operator

FinnNk
oops, also missed the same order part of the question so doesn't answer the original question, but may be of use to someone looking to solve similar problems
FinnNk
+3  A: 

Hmm, maybe it's overkill, but you can use the SequenceMatcher class from difflib:

from difflib import SequenceMatcher 
small_list = [4,2,5]
big_list = [1,2,5,7,2,4,2,5,67,8,5,13,45]
print SequenceMatcher(None, small_list, big_list).get_matching_blocks()

difflib documentation

ephes
+1  A: 

If you know a reasonable bound of your numbers, you can convert them to a Python type whose 'in' operator does this automatically. The two I know are str and unicode.

Then you ask the strings if the smaller is in the larger, this does a substring comparison:

>>> small_list = [4,2,5]
>>> big_list = [1,2,5,7,2,4,2,5,67,8,5,13,45]
>>>
>>> def encode(lst):
      return u"".join(unichr(c) for c in lst)

>>> encode(small_list) in encode(big_list)
True

(You can "encode" to str if all numbers are in 0 <= x <= 255, you can "encode" to unicode if all are in 0 <= x <= sys.maxunicode ).

kaizer.se
A: 

If you want to use the "in" keyword to do what you want, you can override contains using one of the solutions mentioned in the answers here:

class mylist(list):
    def __contains__(self, lst):
        return ':'.join(map(str, lst)) in ':'.join(map(str, self))

small_list = mylist([4,2,5])
big_list = mylist([1,2,5,7,2,4,2,5,67,8,5,13,45])

print small_list in big_list

Edit: Addresses Jeffrey's comment.

Brent Newey
This won't work for two digit numbers, you'd return true for:big_list = [4,2,53]If you really wanted to take this tortured approach and you know your algorithm only needs to work with integers less than max_unicode, see kaizer.se's answer.
Jeffrey Harris
You can use a delimeter like ":" to fix this.
Brent Newey