0

If I created a list:

_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

and tried to get every value <= 6 by using a generator:

test = next(i for i in a for a in _list if i <= 6)

(btw this doesn't work ↑↑↑↑↑)

How do I iterate through lists within a list using a generator? If this is not possible, what method can I use in place of this?

I have looked here: python generator of generators?, but could not find an answer...

flame boi
  • 41
  • 10

5 Answers5

7

Using chain from builtin module itertools:

from itertools import chain

_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

print(list(i for i in chain.from_iterable(_list) if i <= 6))

Output:

[1, 2, 3, 4, 5, 6]

What itertools.chain does? According manual pages:

Make an iterator that returns elements from the first iterable until it is exhausted, then proceeds to the next iterable, until all of the iterables are exhausted. Used for treating consecutive sequences as a single sequence.

Andrej Kesely
  • 168,389
  • 15
  • 48
  • 91
2

in that case, you don't need to create a generator of generator. Just create a double for loop in one generator (to flatten the list, then test for the element values):

_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

gen = (x for sublist in _list for x in sublist if x <= 6)

this double for comprehension syntax needs some using to, comprehensions are generally written "the other way round", but not in the case of loops, hence your confusion. A more general form would be:

(expression(item) for sublist in input_list for item in sublist if condition(item))

then to get the first matching element:

print(next(gen,None))  # None is printed if there's no matching element

(to get all the elements, of course you have to iterate on gen, next provides the "next" values, like if you're iterating "manually" on your generator)

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
0

to nest two fors in the same generator you must reverse the order

test = next(i for a in _list for i in a if i <= 6)
nosklo
  • 217,122
  • 57
  • 293
  • 297
  • When I print `test`, it outputs `1`. Shouldn't it output `1, 2, 3, 4, 5, 6`? – flame boi Jul 10 '18 at 20:36
  • 1
    @flameboi `next()` gets only the next element. If you want all elements use `list()` to fully consume the generator: `test = list(i for a in _list for i in a if i <= 6)` (at that point you can use a list comprehension instead, that always returns a list) – nosklo Jul 10 '18 at 20:38
0

You can combine itertools.takewhile and itertools.chain to create an iterator matching your requirements

>>> from itertools import chain, takewhile
>>> itr = takewhile(lambda i: i<=6, chain(*_list))
>>> print (list(itr))
[1, 2, 3, 4, 5, 6]
Sunitha
  • 11,777
  • 2
  • 20
  • 23
-1
>>> t = (i for a in _list for i in a if i <= 6)
>>> next(t)
1
>>> next(t)
2
>>> next(t)
3
>>> next(t)
4
>>> next(t)
5
>>> 

Use list to convert the iterator to a list

>>> t = (i for a in _list for i in a if i <= 6)
>>> list(t)
[1, 2, 3, 4, 5, 6]
Sunitha
  • 11,777
  • 2
  • 20
  • 23