I'm having a comprehension issue on a specific problem. I have a preexisting nested list, and I want to match and append one value from a different list to the end of each nested list. A quick example of what I've tried, but where I'm stuck:
initial_values = [["First", 1], ["Second", 2], ["Third", 3], ["Fourth", 4]]
other_values = [1,2,3,4]
for sublist in initial_values:
for i in other_values:
sublist.append(i)
print initial_values
This returns [['First', 1, 1, 2, 3, 4], ['Second', 2, 1, 2, 3, 4], ['Third', 3, 1, 2, 3, 4], ['Fourth', 4, 1, 2, 3, 4]]
I want it it to ideally return [['First', 1, 1], ['Second', 2, 2], ['Third', 3, 3], ['Fourth', 4, 4]]
6 Answers 6
You can use zip
to match elements of the same index from different lists. From there on, you're a simple list concatenation away:
[a + [b] for a,b in zip(initial_values, other_values)]
Your double for-loop takes each sublist in turn (the outer for-loop) and appends every element of other_values
to it (the inner for-loop). What you want instead is to add each element of other_values
to the corresponding sublist (i.e. the sublist at the same position/index). Therefore, what you need is only one for-loop:
initial_values = [["First", 1], ["Second", 2], ["Third", 3], ["Fourth", 4]]
other_values = [1,2,3,4]
for i in range(len(initial_values)): # get all the valid indices of `initial_values`
initial_values[i].append(other_values[i])
Here's are some simpler ways to do it:
for i,subl in enumerate(initial_values):
subl.append(other_values[i]))
Or
for subl, val in zip(initial_values, other_values):
subl.append(val)
-
the solution with
enumerate
seems to be the most efficient one. No need to botherzip
for this and create a lot of temporary objects.2016年10月08日 21:18:29 +00:00Commented Oct 8, 2016 at 21:18 -
@Jean-FrançoisFabre: in python3, zip doesn't create temp objects - it returns an iterator with pointers to the original objectsinspectorG4dget– inspectorG4dget2016年10月08日 21:25:15 +00:00Commented Oct 8, 2016 at 21:25
-
I know that, but the tuples inside still have to be created.2016年10月08日 21:54:44 +00:00Commented Oct 8, 2016 at 21:54
-
@Jean-FrançoisFabre: it's still O(1) space, since it's an iterator instead of a full list. Technically
enumerate
andzip
have the same space complexity, though the time complexity may be different due to memory cachinginspectorG4dget– inspectorG4dget2016年10月08日 22:18:28 +00:00Commented Oct 8, 2016 at 22:18 -
I was talking about memory allocation avoided by the use of
enumerate
of course.2016年10月08日 22:21:18 +00:00Commented Oct 8, 2016 at 22:21
It seems like you want to go through both lists with a single iteration. You could achieve that using zip:
for sublist, i in zip(initial_values, other_values):
sublist.append(i)
If you want to use for loop you can try
initial_values = [["First", 1], ["Second", 2], ["Third", 3], ["Fourth", 4]]
other_values = [1,2,3,4]
for i in range(0,len(other_values)):
initial_values[i].append(other_values[i])
print initial_values
output:
[['First', 1, 1], ['Second', 2, 2], ['Third', 3, 3], ['Fourth', 4, 4]]
Built-in function zip will match first item in first list with first item in second list etc.
initial_values = [["First", 1], ["Second", 2], ["Third", 3], ["Fourth", 4]]
other_values = [1,2,3,4]
for initials, other in zip(initial_values, other_values):
initials.append(other)
One of the alternative to achieve it using map()
as:
>>> map(lambda x: x[0] + [x[1]], zip(initial_values, other_values))
[['First', 1, 1], ['Second', 2, 2], ['Third', 3, 3], ['Fourth', 4, 4]]