Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

elegant find sub-list in list

Given a list containing a known pattern surrounded by noise, is there an elegant way to get all items that equal the pattern. See below for my crude code.

list_with_noise = [7,2,1,2,3,4,2,1,2,3,4,9,9,1,2,3,4,7,4,3,1,2,3,5] known_pattern = [1,2,3,4] res = []   for i in list_with_noise:     for j in known_pattern:         if i == j:             res.append(i)             continue  print res 

we would get 2, 1, 2, 3, 4, 2, 1, 2, 3, 4, 1, 2, 3, 4, 4, 3

bonus: avoid appending i if the full pattern is not present (ie., allow 1,2,3,4 but not 1,2,3)

examples:

find_sublists_in_list([7,2,1,2,3,4,2,1,2,3,4,9,9,1,2,3,4,7,4,3,1,2,3,5],[1,2,3,4])  [1,2,3,4],[1,2,3,4],[1,2,3,4]   find_sublists_in_list([7,2,1,2,3,2,1,2,3,6,9,9,1,2,3,4,7,4,3,1,2,6],[1,2,3,4])  [1,2,3],[1,2,3],[1,2,3] 

The lists contain named tuples.

like image 926
Django Doctor Avatar asked Apr 11 '12 13:04

Django Doctor


People also ask

How do I find a sublist in a list?

The subList() method of java. util. ArrayList class is used to return a view of the portion of this list between the specified fromIndex, inclusive, and toIndex, exclusive.

How do you check if a list contains a sublist?

issubset() function. The most used and recommended method to check for a sublist. This function is tailor made to perform the particular task of checking if one list is a subset of another.

How do you check if a list is in a list Python?

To check if the list contains an element in Python, use the “in” operator. The “in” operator checks if the list contains a specific item or not. It can also check if the element exists on the list or not using the list.


1 Answers

I know this question is 5 months old and already "accepted", but googling a very similar problem brought me to this question and all the answers seem to have a couple of rather significant problems, plus I'm bored and want to try my hand at a SO answer, so I'm just going to rattle off what I've found.

The first part of the question, as I understand it, is pretty trivial: just return the original list with all the elements not in the "pattern" filtered out. Following that thinking, the first code I thought of used the filter() function:

def subfinder(mylist, pattern):     return list(filter(lambda x: x in pattern, mylist)) 

I would say that this solution is definitely more succinct than the original solution, but it's not any faster, or at least not appreciably, and I try to avoid lambda expressions if there's not a very good reason for using them. In fact, the best solution I could come up with involved a simple list comprehension:

def subfinder(mylist, pattern):     pattern = set(pattern)     return [x for x in mylist if x in pattern] 

This solution is both more elegant and significantly faster than the original: the comprehension is about 120% faster than the original, while casting the pattern into a set first bumps that up to a whopping 320% faster in my tests.

Now for the bonus: I'll just jump right into it, my solution is as follows:

def subfinder(mylist, pattern):     matches = []     for i in range(len(mylist)):         if mylist[i] == pattern[0] and mylist[i:i+len(pattern)] == pattern:             matches.append(pattern)     return matches 

This is a variation of Steven Rumbalski's "inefficient one liner", that, with the addition of the "mylist[i] == pattern[0]" check and thanks to python's short-circuit evaluation, is significantly faster than both the original statement and the itertools version (and every other offered solution as far as I can tell) and it even supports overlapping patterns. So there you go.

like image 72
mintchkin Avatar answered Oct 02 '22 07:10

mintchkin