Q: What does [i for i] do in this script? [i for i] to me is a ‘null’ statement.
my_list = [1, 2, 3, 2, 4, 2, 5]
indices = [i for i, x in enumerate(my_list) if x == my_list[0]]
print(indices)
Q: What does [i for i] do in this script? [i for i] to me is a ‘null’ statement.
my_list = [1, 2, 3, 2, 4, 2, 5]
indices = [i for i, x in enumerate(my_list) if x == my_list[0]]
print(indices)
That’s because it’s not the full expression. It’s what’s called a “list comprehension”, a way to concisely express building a new list by transforming an existing one. The line is equivalent to the following:
indices = []
for i, x in enumerate(my_list):
if x == my_list[0]:
indices.append(i)
The first i
at the start is the value you’re wanting to add to the finished list. i, x
is an implicit tuple unpacking, retrieving the two values enumerate()
produces.
Got it.
i = (i,x)
I’m not sure what you mean here. A list comprehension looks like this:
[
expression
for variable(s)
in something-iterable
if condition
]
The “if condition” is optional, but you can use it to select just some
of the values from something-iterable
.
The example comprehension went:
[ i for i, x in enumerate(.......) ]
enumerate
yields 2-tuples of the form (index, value)
for each value
in the .......
part. These are unpacked into the variables i
and
x
. The expression
in the example is just i
, which means that the
resulting list would be the index
parts of the 2-tuples.
I don’t know if this makes things more clear or not.
It doesn’t, because the script does not have [i for i]
in it. It has [i for i, x in enumerate(my_list) if x == my_list[0]]
in it. The matching ]
is all the way at the end, and that is important.
This entire thing is called a list comprehension and you can read about them in detail from the tutorial that is built into the official documentation - right here:
Thanks,
Here’s my code:
my_list = [1, 2, 3, 2, 4, 2, 5]
indices = [i for i, x in enumerate(my_list) if x == my_list[1] and x in my_list if x == my_list[1]]
print(indices)
It’s a bit confusing when written like so because there is an implicit tuple there. Python treats the expression as [i for (i, x) in enumerate(my_list) if my_list[0] == x]
.
So its NOT a list with these 2 members:
i for i
x in enumerate(my_list) if my_list[0] == x
Instead, it is equivalent to:
result = []
for iteration in enumerate(my_list):
(i, x) = iteration
if x == my_list[0]:
result.append(i)
Not really an “implicit” tuple (not sure what one would even look like). Commas make tuples. Not parentheses. And there’s an explicit comma there.
There’s an exception: the empty tuple is ()
.
Another edge-case [1] is in generator expressions like the list comprehension here: [i, i for i in range(5)]
doesn’t give you tuples.
although it’s more about order of operations, I suppose ↩︎
Yes, I considered mentioning that, but didn’t want to distract with it. I also wouldn’t feel wrong saying “Humans have two legs”. You likely also wouldn’t use ()
in that context, unless you want to iterate over an iterable of empty iterables and you want to check that they’re all empty.
That said, hmm, it’s actually not even a tuple at all. It’s a “target list”. Doc.
Did you intend to parenthesize that somehow? I’m not sure whether you meant (i, i)
or i, (i for i...)
, and neither does Python. Presumably the latter, since that’s a genexp?
True, and I more often end up making this error when I’m trying to pass a generator to a function that takes an iterable (and I get a different SyntaxError then). I was just being overly pedantic [1] about the “commas define a tuple” statement.
The interpreter actually assumes the former, and suggests I parenthesize my “comprehension target”.
and even worse, technically imprecise! ↩︎
(While we’re on the topic: I feel like there could be clearer terminology than “comprehension target” in that error message.)