4

I want to deep search in a list in Python. For example, I want to know that 5 is in my_list or not.

my_list = [2, [3, 4, [2, 3]], 1, [4, [5]]]

How can I do that?

Paul D. Waite
  • 96,640
  • 56
  • 199
  • 270
mohammad agah
  • 105
  • 1
  • 7

6 Answers6

3

Not sure a quick way to do this with multi-levels of nests, but a recursive algorithm like this would do the trick:

def nestedSearch(nested, v):
    for element in nested:
        if isinstance(element, list):
            if nestedSearch(element, v):
                return True
        elif element == v:
            return True
    return False

You also might look at this for flattening multi-nested lists:

Recursive generator for flattening nested lists

Community
  • 1
  • 1
Sam Mirrado
  • 336
  • 1
  • 2
  • 9
2

You can combine the flatten function (think of it as a recursive version of itertools.chain) with Python's standard in operator (which, on generators, does a linear search) to get this:

>>> def flatten(nested):
    try:
        for sublist in nested:
            for element in flatten(sublist):
                yield element
    except TypeError:
        yield nested


>>> my_list = [2, [3, 4, [2, 3]], 1, [4, [5]]]
>>> 5 in flatten(my_list)
True

Per the comments in the linked question, you will want to refine the flatten code if what you're searching for is iterable - eg, tuples will be flattened into the search just like lists, and searching for strings recurses until it hits Python's stack limit.

Community
  • 1
  • 1
lvc
  • 34,233
  • 10
  • 73
  • 98
1

If you have a list of lists, you can use this approach

>>> l = [[1,2,3],[4,5,6], [7], [8,9]]
>>> [item for sublist in l for item in sublist]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> 5 in [item for sublist in l for item in sublist]
True

Which first flattens the list and the searches through it using O(n).

If your list looks like in your example, I can't think of another way to do it than using for-loops...

Fredrik Pihl
  • 44,604
  • 7
  • 83
  • 130
  • 2
    This only works if you're flattening exactly one level of lists, and each element is guaranteed to also be iterable and not a possible match for the search. That being the case, `5 in itertools.chain.from_iterable(l)` is probably a bit clearer than the list comprehension, and certainly a bit faster (since it doesn't build the full list that will only be used for one single search). – lvc Mar 08 '13 at 12:16
  • that was what I said (or intended to say :-) See http://stackoverflow.com/questions/952914/making-a-flat-list-out-of-list-of-lists-in-python – Fredrik Pihl Mar 08 '13 at 12:33
  • Note that the comments on the accepted answer to that question claim that `list(itertools.chain.from_iterable(l)` is faster than the list comprehensions. The fact that you don't actually *need* a list to do a search (`in` works fine on any iterable) only compounds that. – lvc Mar 08 '13 at 12:48
0

One way for doing it:

def deapSearch(searchElement, searchList):
    for element in searchList:
        if element == searchElement:
            return True
        elif type(element) == type(list):
            found = deapSearch(searchElement, element)
            if found:
                return found
    return False
deapSearch(5, my_list)
True
deapSearch(4, my_list)
True

Not Beautiful but working.

Martin
  • 830
  • 1
  • 7
  • 24
Netwave
  • 40,134
  • 6
  • 50
  • 93
0

I recently needed to do this and needed a simple solution. So I am adding it as an a quick and dirty way to flatten/search a list (may not be a perfect solution but it worked for me).

>>> my_list = [2, [3, 4, [2, 3]], 1, [4, [5]]]
>>> str(5) in str(my_list) # returns True
>>> str(my_list).find(str(5)) # returns the index

Edit: Adding a regex solution as well. But if you have a more complicated case, then you might as well traverse the list.

>>> import re
>>> str(5) in re.findall('(?<=[,\[])([ a-zA-Z0-9 ]+)(?=[,\]])', str(my_list))

The regular expression essentially flattens the list, but won't work for special characters in list items.

AkshayDandekar
  • 421
  • 2
  • 11
-1

if you only have a nested list with integers or chars, one way to solve this problem is to create a list without all unwanted elements ( without '[' , ']' ... ) :

let's say we have a nested list with chars :

>>> nested = [[[[['F', 'B'], 'G'], ['D', 'A']], 'C'], 'E']
>>> string = str(nested)
>>> string = string.replace('[','',len(string))
>>> string = string.replace(']','',len(string))
>>> string = string.replace("'","",len(string))
>>> string = string.replace(" ","",len(string))
>>> string = string.split(',')

it gives :

>>> print (string)
['F', 'B', 'G', 'D', 'A', 'C', 'E']

Now you can search easily without any loop :

>>> 'F' in string
True
  • one thing you must take in consideration is that an integer nested list is more expensive in memory than a simple string, and a recursive function is not the simplest way to deal with such a problem because of the iteration depth limit. The big advantage in using Python is that you can search in a string the same way you search in a list – Wassim Tair Nov 19 '14 at 13:21