Flatten tuples in a nested list - python

is there a compact oneliner or python idiom to handle the following task?
I want to transform a list of list of tuples like this:
input = [[(1,2,3),(4,5,6)],[(7,8,9),(10,11,12)]]
to this:
output [[1,2,3,7,8,9], [4,5,6,10,11,12]]
Using map and flattening the list only gave me the follwing
input_trans = map(list, zip(*input))
input_trans_flat = [item for sublist in input_trans for item in sublist]
Out: [(1, 2, 3), (7, 8, 9), (4, 5, 6), (10, 11, 12)]
Many Thanks in Advance!

I'd do:
output = [list(a + b) for a, b in zip(*input)]
The zip part, as you already know, transposes the outer list of lists. Then I grab each pair of tuples and concatenate them, then turn the combined tuple into a list. If you don't care if you have a list of lists or a list of tuples in the end, you could get rid of the list call.

You should be able to generalise Blckknght's answer to any number of tuples inside a list, using sum.
output = [list(sum(x, ())) for x in zip(*input)]
print(output)
[[1, 2, 3, 7, 8, 9], [4, 5, 6, 10, 11, 12]]

You can use list comprehension with zip() like below:
output = [[item for tup in (i, j) for item in tup] for i, j in zip(*input)]
Output:
>>> input = [[(1, 2, 3), (4, 5, 6)], [(7, 8, 9), (10, 11, 12)]]
>>>
>>> output = [[item for tup in (i, j) for item in tup] for i, j in zip(*input)]
>>> output
[[1, 2, 3, 7, 8, 9], [4, 5, 6, 10, 11, 12]]

Here's one way.
from itertools import chain
l = [[(1,2,3),(4,5,6)],[(7,8,9),(10,11,12)]]
[list(chain.from_iterable(s)) for s in l]
gives me
[[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12]]

Related

Creating two 1D lists from python based on function returning two entries

I have a function f(x,y) which returns two values a,b.
I want to construct a 2D List from returned values of a,b from f being called on x in a List of values and y in an equally long list of values.
Is there an easy way to do this?
I tried this and it did not work.
aList, bList = [f(x[i],y[i],1) for i in range(T)]
You can use the the *-operator to perform argument unpacking of the list while calling zip() to compose the two desired lists.
input_data = [(0, 0), (1, 1), (2, 2)]
def f(x, y):
return x+1, y-1
results = [f(i[0], i[1]) for i in input_data]
print (f"results: {results}")
a_list, b_list = zip(*results)
print(f"a_list: {a_list}\nb_list: {b_list}")
# This is equivalent to what the *-operator does above, in that
# it is unpacking the list of tuples into a series of arguments
# to zip().
a_list2, b_list2 = zip(results[0], results[1], results[2])
print(f"a_list2: {a_list2}\nb_list2: {b_list2}")
Output:
$ python3 solution.py
results: [(1, -1), (2, 0), (3, 1)]
a_list: (1, 2, 3)
b_list: (-1, 0, 1)
a_list2: (1, 2, 3)
b_list2: (-1, 0, 1)
Using the *-operator for unpacking is convenient because it can seamlessly scale with the number of arguments to zip().
import random
def f(num_results):
return tuple(random.randint(1,10) for n in range(num_results))
for num_results in range(4,7):
print(f"\nHandling {num_results} values per tuple...")
results = [f(num_results) for _ in range(3)]
print(f"results: {results}")
# Note the use unpacking in the assignment as well to
# capture a variable number of lists.
*x_lists, = zip(*results)
for *x_list, in x_lists:
print(x_list)
Output:
$ python3 solution2.py
Handling 4 values per tuple...
results: [(4, 5, 7, 1), (8, 9, 9, 3), (6, 3, 9, 4)]
[4, 8, 6]
[5, 9, 3]
[7, 9, 9]
[1, 3, 4]
Handling 5 values per tuple...
results: [(6, 3, 3, 9, 9), (10, 1, 1, 5, 4), (3, 10, 8, 3, 2)]
[6, 10, 3]
[3, 1, 10]
[3, 1, 8]
[9, 5, 3]
[9, 4, 2]
Handling 6 values per tuple...
results: [(5, 5, 10, 8, 1, 6), (7, 5, 8, 7, 9, 1), (5, 5, 1, 1, 10, 5)]
[5, 7, 5]
[5, 5, 5]
[10, 8, 1]
[8, 7, 1]
[1, 9, 10]
[6, 1, 5]
You always need to think about what you HAVE vs what you WANT. The list comprehension returns a single list containing 2-tuples. You need to split that list.
result = [f(x[i],y[i],1) for i in range(T)]
aList = [k[0] for k in result]
bList = [k[1] for k in result]

Adding and creating chunks of a list in python

This is my list
list1 = [1,2,3,4,5,6,7,8,9,10,11,12]
i tried to do this
it = iter(list1)
chunked_lists = zip(it,it,it)
chunked_lists is now = [(1,2,3),(4,5,6),(7,8,9),(10,11,12)]
Now i'd like to add a 'data' to every chunk so that it would look like
[(1,2,3,'data'),(4,5,6,'data')....etc]
but tuples are immutable and i'd have to destroy them, append and create them again.
is there a better way to accomplish this in python?
it = iter(list1)
from itertools import repeat
chunked_lists = zip(it,it,it,repeat("data"))
[(1, 2, 3, 'data'), (4, 5, 6, 'data'), (7, 8, 9, 'data'), (10, 11, 12, 'data')]
You can use itertools.repeat to create a new iterator contain the data and then apply the zip function on your prior iterators and new repeated iterator :
>>> it = iter(list1)
>>> it2=repeat('data',len(list1))
>>> chunked_lists = zip(it,it,it,it2)
>>> chunked_lists
[(1, 2, 3, 'data'), (4, 5, 6, 'data'), (7, 8, 9, 'data'), (10, 11, 12, 'data')]
>>>
Note that as #Padraic Cunningham mentioned on his answer there is no need to call the len function in itertools.repeat.So you can simply use repeat('data')
If you want to modify the list of tuples after creation you can use a list comprehension to modify your tuples by adding the new elements to the tuples.
Example :
>>> import numpy as np
>>> l2=np.random.randint(0,100,len(list1)/3)
>>> it = iter(list1)
>>> chunked_lists = zip(it,it,it)
>>> chunked_lists = [i+(j,) for i,j in zip(chunked_lists,l2)]
>>> l2
array([35, 22, 35, 95])
>>> chunked_lists
[(1, 2, 3, 35), (4, 5, 6, 22), (7, 8, 9, 35), (10, 11, 12, 95)]
>>>
This should be a linear time way to do it:
list1 = [1,2,3,4,5,6,7,8,9,10,11,12]
result = [tuple(list1[x:x+3]+["data"]) for x in range(0, len(list1), 3)]
If I am not ignoring some Python intricacy, since tuple() has complexity O(n), the slice accessor has complexity O(k) and the overhead caused by the +["data"] isn't greater than simply appending a node at the end of a list (which is O(1)), it should be O((len(list1) / k) * k ^ 2) aka O(n k), where k is fixed to 3 in your case.
result = [tuple(list1[x:x+3]+["data"]) for x in range(0, len(list1), 3)]
means:
[list1[x:x+3]+["data"] for x in (0, 3, ... 12)]
aka:
[
tuple(list1[0:3]+["data"]),
tuple(list1[4:6]+["data"]),
...
tuple(list1[9:12]+["data"])
]
It is also well behaved with odd lists:
>>> list1 = [1,2,3,4,5,6,7,8,9,10,11]
>>> print [tuple(list1[x:x+3]+["data"]) for x in range(0, len(list1), 3)]
[(1, 2, 3, 'data'), (4, 5, 6, 'data'), (7, 8, 9, 'data'), (10, 11, 'data')]
Since tuples are immutable, if you're adding and deleting from them often, you're perhaps better off using lists of lists:
list1 = [1,2,3,4,5,6,7,8,9,10,11,12]
it = iter(list1)
chunked_lists = [list(a) for a in zip(it,it,it)]
# => [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
for l in chunked_lists:
l.append('data')
# => [[1, 2, 3, 'data'], [4, 5, 6, 'data'], [7, 8, 9, 'data'], [10, 11, 12, 'data']]
How about adding them to the zip function when you are creating the chunked_lists itself -
>>> list1 = [1,2,3,4,5,6,7,8,9,10,11,12]
>>> it = iter(list1)
>>> chunked_lists = zip(it,it,it,['data']*(len(list1)/3))
>>> chunked_lists
[(1, 2, 3, 'data'), (4, 5, 6, 'data'), (7, 8, 9, 'data'), (10, 11, 12, 'data')]
For Python 3.x , you would need to divide the len(list1) using // operator (for it to return int) . (And most probably wrap zip in list() , since zip in Python 3.x , returns an iterator.)

Sum lists of variable lengths element-wise

If I have a list of lists, and each nested list contains numbers, how can I add all of these lists element-wise into a single array?
i.e.
listOne = [1, 2, 3]
listTwo = [4, 5, 6]
listThree = [7, 8, 9, 10]
allLists = [listOne, listTwo, listThree]
total = add(allLists)
print total
output should be [12, 15, 18, 10]
Use izip_longest to remap rows/columns (like zip but to the longest element rather than shortest), filling shorter items 0
from itertools import izip_longest
total = [sum(x) for x in izip_longest(*allLists, fillvalue=0)]
Outputs:
[12, 15, 18, 10]
Also for your edification, the intermediate output of the zip_longest is:
[(1, 4, 7), (2, 5, 8), (3, 6, 9), (0, 0, 10)]
This is also a nice opportunity to practice list comprehensions ;)
maxlen = max(len(lst) for lst in allLists) # find length of longest list
sumlist = [sum([lst[i] if i<len(lst) else 0 for lst in allLists]) for i in range(maxlen)]
gives sumlist
[12, 15, 18, 10]

zipping a python dict of lists

I have a python dictionary of type defaultdict(list)
This dictionary is something like this:
a = {1:[1,2,3,4],2:[5,6,7,8]....n:[some 4 elements]}
So basically it has n keys which has a list as values and all the list are of same lenght.
Now, i want to build a list which has something like this.
[[1,5,...first element of all the list], [2,6.. second element of all the list]... and so on]
Soo basically how do i get the kth value from all the keys.. Is there a pythonic way to do this.. ??
THanks
>>> a = {1:[1,2,3,4],2:[5,6,7,8], 3:[9, 10, 11, 12]}
>>>
>>> zip(*(a[k] for k in sorted(a)))
[(1, 5, 9), (2, 6, 10), (3, 7, 11), (4, 8, 12)]
(Okay, this produces tuples, not lists, but hopefully that's not a problem.)
Update: I like the above more than this, but the following is a few keystrokes shorter:
>>> zip(*map(a.get, sorted(a)))
[(1, 5, 9), (2, 6, 10), (3, 7, 11), (4, 8, 12)]
How about this solution:
zip(*a.values())
For e.g.
>>> a = {1:[1,2,3,4],2:[5,6,7,8], 3:[9, 10, 11, 12]}
>>> zip(*a.values())
[(1, 5, 9), (2, 6, 10), (3, 7, 11), (4, 8, 12)]
Update: to preserve order use DSM's answer.
An alternative way to do this using numpy:
>>> import numpy
>>> a = {1:[1,2,3,4],2:[5,6,7,8], 3:[9, 10, 11, 12]}
>>> x = numpy.zeros((len(a),4), dtype=int)
>>> x[[i-1 for i in a.keys()]] = a.values()
>>> x.T
array([[ 1, 5, 9],
[ 2, 6, 10],
[ 3, 7, 11],
[ 4, 8, 12]])
List comprehension makes this easy. To get a list of the kth items:
k = 1
[a[key][k] for key in sorted(a.keys())]
The to build a list of lists:
[ [a[key][k] for key in sorted(a.keys())] for k in range(len(a[1]))]
if you want list of lists (assuming each list is of length=4):
>>> a = {1:[1, 2, 3, 4], 2:[5, 6, 7, 8], 3:[9, 10, 11, 12]}
>>> [[a[key][x] for key in sorted(a.keys())] for x in xrange(4)]
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

List Python Operation

I got this list:
input = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
I want to make new lists with each index item:
i.e.
output = [[1,5,9],[2,6,10],[3,7,11],[4,8,12]]
This is a canonical example of when to use zip:
In [6]: inlist = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
In [7]: out=zip(*inlist)
In [8]: out
Out[8]: [(1, 5, 9), (2, 6, 10), (3, 7, 11), (4, 8, 12)]
Or, to get a list of lists (rather than list of tuples):
In [9]: out=[list(group) for group in zip(*inlist)]
In [10]: out
Out[10]: [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
Use zip():
input = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
output = zip(*input)
This will give you a list of tuples. To get a list of lists, use
output = map(list, zip(*input))

Categories

Resources