Reputation: 7895
I have this variable:
myList = [
range(27,35),
range(19,27),
range(11,19),
range(92,100),
range(125,133)
]
I would like to search the list for an item (lets say 98) and return the index of the list containing that item (in this case 3).
I found this: https://stackoverflow.com/a/2206174/788054. It seems great, however I'm having trouble adapting it to lists, and generators confuse me.
Upvotes: 1
Views: 67
Reputation: 239443
You can create a generator expression like this and get the next value with the next
function
next(idx for idx, item in enumerate(myList) if 98 in item)
# 3
This can be understood like this
for idx, item in enumerate(myList):
if 98 in item:
print idx
The difference between generator/generator expression and normal functions/code are as follows
They will not be evaluated till we invoke them (lazy evaluation). For example, consider this list comprehension
a = [idx for idx, item in enumerate(myList) if 98 in item]
print a
[3]
this executes immediately and gives the results. But, the gen exps are not like this
a = (idx for idx, item in enumerate(myList) if 98 in item)
print(a)
# <generator object <genexpr> at 0x7f599213b3a8>
it returns a generator object. We have to manually invoke it with next
protocol.
They don't exhaust with the execution immediately. For example, lets say there are more than one matches
print([idx for idx, item in enumerate([1, 2, 3, 4]) if item % 2])
# [0, 2]
LC immediately returns both the indexes. But, when we use GenExp with next
prototcol, it yields the first index, retains the current execution context and transfers the control to the invoker. When we call next
on it again, it resumes the execution from where it left of.
gen_exp = ((idx for idx, item in enumerate([1, 2, 3, 4]) if item % 2))
print(next(gen_exp))
# 0
print(next(gen_exp))
# 2
print(next(gen_exp))
# StopIteration
Note: When the generators are exhausted they raise StopIteration
.
This is really helpful, when you need to iterate over a huge list of items, or processing a huge file, you don't have to store the entire list/file in memory. You can simply iterate over the contents, process them and move on to the next chunk.
Note:
Once the generators are exhausted they cannot be used again. You need to create a new generator.
You cannot skip or move backwards in a generator. Its a single step, forward only iterator.
Generators are best suitable for iteration. But if you want to convert the list of values from a generator to a list, you can simply use list
function. For example,
print([idx for idx, item in enumerate([1, 2, 3, 4]) if item % 2])
# [0, 2]
gen_exp = ((idx for idx, item in enumerate([1, 2, 3, 4]) if item % 2))
print(list(gen_exp))
# [0, 2]
Upvotes: 1