Duplicating list items variable number of times with list comprehension
Question:
I am basically trying to get my head around using a list comprehension with this basic bit of code. Im trying to duplicate a list item by the value of the list item:
y = [1, 2, 0, 1]
x = []
for i in y:
for j in range(i):
x.append(i)
# Desired output
>>> [1, 2, 2, 1]
x = [i for _ in range(i) for i in y]
# Wrong output
>>> [1, 2, 0, 1]
# Right output
x = [j for j in y for _ in range(j)]
>>> [1, 2, 2, 1]
I just cant seem to get my head around why I get the wrong output for the second example. Could someone explain what is wrong here. Thanks.
Answers:
The right comprehension is:
x = [i for i in y for j in range(i)]
This give the result you want
item for item in list range(item) times
inspired by this thread
flattened = [val for sublist in list_of_lists for val in sublist]
x = [j for j in y for i in range(j)]
When you have multiple for
loops inside a list comprehension, the loops are processed in the same order as they would be using “traditional” for
loops. Your list comp that gives the correct output has the loops in the same order as your code at the start using .append
with traditional for
loops.
As Rahul mentions in the comments, in isolation,
x = [i for _ in range(i) for i in y]
would give a
NameError: name 'i' is not defined
It doesn’t in this case because i
was defined by the earlier code.
In contrast, look at what happens with a nested list comp:
y = [1, 2, 0, 1]
x = [[j for j in range(i)] for i in y]
print(x)
output
[[0], [0, 1], [], [0]]
Here, the outermost loop is in the outer comprehension and the inner loop is in the inner comprehension. So for each iteration of the for i in y
we create a new list comp, and in that list comp we loop over range(i)
.
I am basically trying to get my head around using a list comprehension with this basic bit of code. Im trying to duplicate a list item by the value of the list item:
y = [1, 2, 0, 1]
x = []
for i in y:
for j in range(i):
x.append(i)
# Desired output
>>> [1, 2, 2, 1]
x = [i for _ in range(i) for i in y]
# Wrong output
>>> [1, 2, 0, 1]
# Right output
x = [j for j in y for _ in range(j)]
>>> [1, 2, 2, 1]
I just cant seem to get my head around why I get the wrong output for the second example. Could someone explain what is wrong here. Thanks.
The right comprehension is:
x = [i for i in y for j in range(i)]
This give the result you want
item for item in list range(item) times
inspired by this thread
flattened = [val for sublist in list_of_lists for val in sublist]
x = [j for j in y for i in range(j)]
When you have multiple for
loops inside a list comprehension, the loops are processed in the same order as they would be using “traditional” for
loops. Your list comp that gives the correct output has the loops in the same order as your code at the start using .append
with traditional for
loops.
As Rahul mentions in the comments, in isolation,
x = [i for _ in range(i) for i in y]
would give a
NameError: name 'i' is not defined
It doesn’t in this case because i
was defined by the earlier code.
In contrast, look at what happens with a nested list comp:
y = [1, 2, 0, 1]
x = [[j for j in range(i)] for i in y]
print(x)
output
[[0], [0, 1], [], [0]]
Here, the outermost loop is in the outer comprehension and the inner loop is in the inner comprehension. So for each iteration of the for i in y
we create a new list comp, and in that list comp we loop over range(i)
.