Unpack a nested list - python

My question is simple.
There are two lists.
The first is a list of integers:
a = [1, 2, 3]
The other is a list of lists:
b = [['a', 'b'], ['c', 'd'], ['e', 'f']]
How could I get the result below:
result = [[1, 'a', 'b'], [2, 'c', 'd'], [3, 'e', 'f']]
Thanks.

>>> a = [1, 2, 3]
>>> b = [['a', 'b'], ['c', 'd'], ['e', 'f']]
>>> [[aa] + bb for aa, bb in zip(a, b)]
[[1, 'a', 'b'], [2, 'c', 'd'], [3, 'e', 'f']]

In Python3
>>> a = [1, 2, 3]
>>> b = [['a', 'b'], ['c', 'd'], ['e', 'f']]
>>> [aa+bb for *aa, bb in zip(a,b)]
[[1, 'a', 'b'], [2, 'c', 'd'], [3, 'e', 'f']]

Another way to do this would be:
index = 0
l = b
for i in a:
l[index].append(i)
index += 1

The following Python code will unpack each list and assemble it in the form you indicated.
[[a[i]] + b[i] for i in range(min(len(a),len(b)))]

Using Python's enumerate function you can loop over a list with an index. Using x.extend(y) will prepend the values in list x to list y.
a = [1, 2, 3]
b = [['a', 'b'], ['c', 'd'], ['e', 'f']]
result = []
for index, value in enumerate(a):
aa = [value]
aa.extend(b[index])
result.append(aa)

Related

Generate All Replacements for List of Lists

I'm building an application in Python where I need to define the following sort of function:
generate_replacements(['a', 'b', ['c', ['e', 'f']]], 1)
The expected output is all possible versions of the input list where just one element has been replaced
[
[1, 'b', ['c', ['e', 'f']]],
['a', 1, ['c', ['e', 'f']]],
['a', 'b', 1],
['a', 'b', [1, ['e', 'f']]],
['a', 'b', ['c', 1]],
['a', 'b', ['c', [1, 'f']]],
['a', 'b', ['c', ['e', 1]]]
]
I can see that recursion is the way to go, but I'm really stuck figuring out how to even best start this.
You can generate the replacements from the list, then if you notice you are replacing a list, also pass that list back through the function recursively. This is made a bit simpler if you use a generator:
def generate_replacements(l, rep):
for i in range(len(l)):
yield l[0:i] + [rep] + l[i+1: ]
if isinstance(l[i], list):
yield from (l[0:i] + [rec] + l[i+1: ]
for rec in generate_replacements(l[i], rep))
list(generate_replacements(['a', 'b', ['c', ['e', 'f']]], 1))
This give:
[[1, 'b', ['c', ['e', 'f']]],
['a', 1, ['c', ['e', 'f']]],
['a', 'b', 1],
['a', 'b', [1, ['e', 'f']]],
['a', 'b', ['c', 1]],
['a', 'b', ['c', [1, 'f']]],
['a', 'b', ['c', ['e', 1]]]]

Join tuples inside list

I have:
mylist = [(['a', 'b'], [1, 2]), (['c', 'd'], [3])]
I need one list with the letters and one with the numbers, like this:
(['a', 'b', 'c', 'd'], [1, 2, 3])
I have made some efforts, but I could just get one list with the letters, not both:
answer = [item for sublist in mylist for item in sublist[0]]
#returns ['a', 'b', 'c', 'd']
answer = [[item for sublist in mylist for item in sublist[i]] for i in range(2)]
Just need to iterate through your sublist :)
Here's a simple alternative using zip and itertools.chain:
from itertools import chain
[list(chain.from_iterable(i)) for i in zip(*mylist)]
# [['a', 'b', 'c', 'd'], [1, 2, 3]]
zip works as well:
tuple(map(lambda x: x[0]+x[1], zip(mylist[0], mylist[1])))
Code:
mylist = [(['a', 'b'], [1, 2]), (['c', 'd'], [3])]
print(tuple(map(lambda x: x[0]+x[1], zip(mylist[0], mylist[1]))))
# (['a', 'b', 'c', 'd'], [1, 2, 3])

How can I copy each element of a list a distinct, specified number of times?

I am using python 3 and I want to create a new list with elements from a the first list repeated as many times as the respective number of the second list
For example:
char = ['a', 'b', 'c']
int = [2, 4, 3]
result = ['a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'c']
Thx all for help
One-liner solution
Iterate over both lists simultaneously with zip, and create sub-lists for each element with the correct length. Join them with itertools.chain:
# from itertools import chain
list(chain(*([l]*n for l, n in zip(char, int))))
Output:
['a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'c']
char = ['a', 'b', 'c']
ints = [2, 4, 3]
Solution 1: Using numpy
import numpy as np
result = np.repeat(char, ints)
Solution 2: Pure python
result = []
for i, c in zip(ints, char):
result.extend(c*i)
Output:
['a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'c']
Using zip
Ex:
c = ['a', 'b', 'c']
intVal = [2, 4, 3]
result = []
for i, v in zip(c, intVal):
result.extend(list(i*v))
print(result)
Output:
['a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'c']
With for loops, very basic:
results = list()
for k, i in enumerate(integers):
results_to_add = char[k]*i
results.extend(results_to_add)
char = ['a', 'b', 'c']
rep = [2, 4, 3]
res = [c*i.split(",") for i,c in zip(char, rep )] # [['a', 'a'], ['b', 'b', 'b', 'b'], ['c', 'c', 'c']]
print([item for sublist in res for item in sublist]) # flattening the list
EDIT:
one-liner using itertools.chain:
print(list(chain(*[c*i.split(",") for (i,c) in zip(char, int)])))
OUTPUT:
['a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'c']
One liner using list-comprehension and sum(list_, []).
sum([[x]*y for x,y in zip(char_, int_)], [])
>>> char_ = ['a', 'b', 'c']
>>> int_ = [2, 4, 3]
>>> print(sum([[x]*y for x,y in zip(char_, int_)], []))
>>> ['a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'c']
Alternative:
list(itertools.chain.from_iterable([[x]*y for x,y in zip(char_, int_)]))
Looks like it is faster than using itertools.
>>> timeit.repeat(lambda:list(itertools.chain.from_iterable([[x]*y for x,y in zip(char_, int_)])), number = 1000000)
[1.2130177360377274, 1.115080286981538, 1.1174913379945792]
>>> timeit.repeat(lambda:sum([[x]*y for x,y in zip(char_, int_)], []), number = 1000000)
[1.0470570910256356, 0.9831087450147606, 0.9912429330288433]

Sequence numbers for lists with lists

I am preparing a list of lists. the initial list can contain any number of entries but the sub-lists each contain 3 entries, eg:
colony = [['A', 'B', 'C'], [1, 'b', 'c'], [2, 'b', 'c'], [3, 'b', 'c'], [4, 'b', 'c'], [5, 'b', 'c']]
The first entry in each of the sub-lists is the sequence number of the entry and needs to be sequential,
ie. 1, 2, 3, 4, 5, 6,...
A, B and C are the column headings, the data is in the subsequent lists. My difficulty is that if the number of sub-lists that I need to add is say 5, then the sequence number of every entry is 5.How can I change my code to insert the correct sequence number in each sub-list:
colony = [['A', 'B', 'C']]
add_colony = [0, 0, 0]
R = 5
i = 1
for i in range(R):
add_colony[0] = i + 1
add_colony[1] = 'b'
add_colony[2] = 'c'
colony.append(add_colony)
i = i + 1
print()
print('colony = ', colony)
produces:
colony = [['A', 'B', 'C'], [5, 'b', 'c'], [5, 'b', 'c'], [5, 'b', 'c'], [5, 'b', 'c'], [5, 'b', 'c']]
not:
colony = [['A', 'B', 'C'], [1, 'b', 'c'], [2, 'b', 'c'], [3, 'b', 'c'], [4, 'b', 'c'], [5, 'b', 'c']]
I have tried all sorts of variations but end up with the incorrect output.
Thanks in advance
Bob
You are permanently mutating and appending the same list object add_colony. All the lists in colony are references to this same object. You have to create a new list for each loop iteration:
for i in range(R):
add_colony = [0, 0, 0] # without this line ...
add_colony[0] = i + 1 # ... this mutation will affect all the references in colony
add_colony[1] = 'b'
add_colony[2] = 'c'
colony.append(add_colony)
Or shorter:
for i in range(R):
colony.append([i + 1, 'b', 'c'])
Hello there fellow University of Melbourne Student!
As #schwobaseggl mentioned, you need to create a new list object on each iteration of your loop, or you just keep appending the same object over and over again. You could also just make add_colony have the default values ['b', 'c'], and insert() the new i value at the beginning each of the list.
Here is an example:
colony = [['A', 'B', 'C']]
R = 5
for i in range(R):
add_colony = ['b', 'c']
add_colony.insert(0, i+1)
colony.append(add_colony)
print('colony = ', colony)
Which Outputs:
colony = [['A', 'B', 'C'], [1, 'b', 'c'], [2, 'b', 'c'], [3, 'b', 'c'], [4, 'b', 'c'], [5, 'b', 'c']]
You could also use a list comprehension:
colony = [['A', 'B', 'C']] + [[i + 1] + ['b', 'c'] for i in range(R)]
Good Luck!
1 liner list comp that mutates the original list without saving it to a variable (kinda weird):
[colony.append([i, 'b', 'c']) for i in range(1, R + 1)]
print(colony) outputs
[['A', 'B', 'C'], [1, 'b', 'c'], [2, 'b', 'c'], [3, 'b', 'c'], [4, 'b', 'c'], [5, 'b', 'c']]

python: combine lists of lists for SQLITE table

I need to combine 3 lists into one list so that I can insert it smoothly into sqlite table.
list1= [[a1,b1,c1],[a2,b2,c2]]
list2= [[d1,e1,f1],[d2,e2,f2]]
Output should look like:
combined_list = [[a1,b1,c1,d1,e1,f1],[a2,b2,c2,d2,e2,f2]]
I tried sum list1 + list2 but both didn't work as this output.
You can try this:
from operator import add
a=[[1, 2, 3], [4, 5, 6]]
b=[['a', 'b', 'c'], ['d', 'e', 'f']]
print a + b
print map(add, a, b)
Output:
[[1, 2, 3], [4, 5, 6], ['a', 'b', 'c'], ['d', 'e', 'f']]
[[1, 2, 3, 'a', 'b', 'c'], [4, 5, 6, 'd', 'e', 'f']]
Edit:
To add more than two arrays:
u=[[]]*lists[0].__len__()
for x in lists:
u=map(add, u, x)

Categories