I have a list that contains nested lists and I need to know the most efficient way to search within those nested lists.
e.g., if I have
[[\'a\',\'b\
>>> lis=[['a','b','c'],['d','e','f']]
>>> any('d' in x for x in lis)
True
generator expression using any
$ python -m timeit -s "lis=[['a','b','c'],['d','e','f'],[1,2,3],[4,5,6],[7,8,9],[10,11,12],[13,14,15],[16,17,18]]" "any('d' in x for x in lis)"
1000000 loops, best of 3: 1.32 usec per loop
generator expression
$ python -m timeit -s "lis=[['a','b','c'],['d','e','f'],[1,2,3],[4,5,6],[7,8,9],[10,11,12],[13,14,15],[16,17,18]]" "'d' in (y for x in lis for y in x)"
100000 loops, best of 3: 1.56 usec per loop
list comprehension
$ python -m timeit -s "lis=[['a','b','c'],['d','e','f'],[1,2,3],[4,5,6],[7,8,9],[10,11,12],[13,14,15],[16,17,18]]" "'d' in [y for x in lis for y in x]"
100000 loops, best of 3: 3.23 usec per loop
How about if the item is near the end, or not present at all? any
is faster than the list comprehension
$ python -m timeit -s "lis=[['a','b','c'],['d','e','f'],[1,2,3],[4,5,6],[7,8,9],[10,11,12],[13,14,15],[16,17,18]]"
"'NOT THERE' in [y for x in lis for y in x]"
100000 loops, best of 3: 4.4 usec per loop
$ python -m timeit -s "lis=[['a','b','c'],['d','e','f'],[1,2,3],[4,5,6],[7,8,9],[10,11,12],[13,14,15],[16,17,18]]"
"any('NOT THERE' in x for x in lis)"
100000 loops, best of 3: 3.06 usec per loop
Perhaps if the list is 1000 times longer? any
is still faster
$ python -m timeit -s "lis=1000*[['a','b','c'],['d','e','f'],[1,2,3],[4,5,6],[7,8,9],[10,11,12],[13,14,15],[16,17,18]]"
"'NOT THERE' in [y for x in lis for y in x]"
100 loops, best of 3: 3.74 msec per loop
$ python -m timeit -s "lis=1000*[['a','b','c'],['d','e','f'],[1,2,3],[4,5,6],[7,8,9],[10,11,12],[13,14,15],[16,17,18]]"
"any('NOT THERE' in x for x in lis)"
100 loops, best of 3: 2.48 msec per loop
We know that generators take a while to set up, so the best chance for the LC to win is a very short list
$ python -m timeit -s "lis=[['a','b','c']]"
"any('c' in x for x in lis)"
1000000 loops, best of 3: 1.12 usec per loop
$ python -m timeit -s "lis=[['a','b','c']]"
"'c' in [y for x in lis for y in x]"
1000000 loops, best of 3: 0.611 usec per loop
And any
uses less memory too
If your arrays are always sorted as you show, so that a[i][j] <= a[i][j+1]
and a[i][-1] <= a[i+1][0]
(the last element of one array is always less than or equal to the first element in the next array), then you can eliminate a lot of comparisons by doing something like:
a = # your big array
previous = None
for subarray in a:
# In this case, since the subarrays are sorted, we know it's not in
# the current subarray, and must be in the previous one
if a[0] > theValue:
break
# Otherwise, we keep track of the last array we looked at
else:
previous = subarray
return (theValue in previous) if previous else False
This kind of optimization is only worthwhile if you have a lot of arrays and they all have a lot of elements though.
Using list comprehension, given:
mylist = [['a','b','c'],['d','e','f']]
'd' in [j for i in mylist for j in i]
yields:
True
and this could also be done with a generator (as shown by @AshwiniChaudhary)
Update based on comment below:
Here is the same list comprehension, but using more descriptive variable names:
'd' in [elem for sublist in mylist for elem in sublist]
The looping constructs in the list comprehension part is equivalent to
for sublist in mylist:
for elem in sublist
and generates a list that where 'd' can be tested against with the in
operator.
if you just want to know that your element is there in the list or not then you can do this by converting list to string and check it. you can extend this of more nested list . like [[1],'a','b','d',['a','b',['c',1]]] this method is helpful iff you dont know that level of nested list and want to know that is the searchable item is there or not.
search='d'
lis = [['a',['b'],'c'],[['d'],'e','f']]
print(search in str(lis))
Use a generator expression, here the whole list will not be traversed as generator generate results one by one:
>>> lis = [['a','b','c'],['d','e','f']]
>>> 'd' in (y for x in lis for y in x)
True
>>> gen = (y for x in lis for y in x)
>>> 'd' in gen
True
>>> list(gen)
['e', 'f']
~$ python -m timeit -s "lis=[['a','b','c'],['d','e','f'],[1,2,3],[4,5,6],[7,8,9],[10,11,12],[13,14,15],[16,17,18]]" "'d' in (y for x in lis for y in x)"
100000 loops, best of 3: 2.96 usec per loop
~$ python -m timeit -s "lis=[['a','b','c'],['d','e','f'],[1,2,3],[4,5,6],[7,8,9],[10,11,12],[13,14,15],[16,17,18]]" "'d' in [y for x in lis for y in x]"
100000 loops, best of 3: 7.4 usec per loop