tijko
tijko

Reputation: 8292

Creating a list of integers from a nested list?

I have a nested list, like this one for example:

 test = [[15, [7, [None], [11, [None], [13, [None], [None]]]], [None]], [20, [None], [None]]] 

I was wanting to create another list from this with only integers contained in the nest. Which would return this:

[15, 7, 11, 13, 20]

I have made this recursive function to do what I needed to accomplish but, I couldn't help to think this isn't the best way to go about it. Is there a more pythonic or efficient way to do it?

def nest_search(nest, hold=[]):
    for item in nest:
        if isinstance(item, int):
            hold.append(item)
        if isinstance(item, list):
            nest_search(item, hold)
    return hold

>>> print nest_search(test)
[15, 7, 11, 13, 20]

Upvotes: 0

Views: 287

Answers (2)

Aesthete
Aesthete

Reputation: 18848

Using a flatten solution posted here, you could try something like the following.

>>> def flatten(x):
    try:
      it = iter(x)
    except TypeError:
      yield x
    else:
      for i in it:
        for j in flatten(i):
          yield j
>>> filter(bool, flatten(test))
[15, 7, 11, 13, 20]

I think the use of two separate functions flatten and filter is clearer, and you encourage modularity, allowing one to be used without the other.

Upvotes: 1

Blckknght
Blckknght

Reputation: 104712

The only thing I see that's unpythonic is the default argument. See this question for why that won't work the way your expect.

Here's how I'd fix it:

def nest_search(nest, hold=None):
    if hold is None:
        hold = []
    for item in nest:
        if isinstance(item, int):
            hold.append(item)
        if isinstance(item, list):
            nest_search(item, hold)
    return hold

An alternative implementation would be to make the function a generator, which yields the values one by one, rather than adding them to a list that it returns at the end. (If you do need a list, just wrap the generator call in the list constructor).

def nest_search_gen(nest):
    for item in nest:
        if isinstance(item, int):
            yield item
        if isinstance(item, list):
            yield from nest_search_gen(item)

This uses the new yield from syntax introduced in Python 3.3. If you are using an earlier version, you can get the same effect by replacing the last line with:

for i in nest_search_gen(item):
    yield i

Upvotes: 2

Related Questions