Related
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]]
How 'pythonic-ly', do I turn this:
[[x1,y1], [x2,y2]]
Into:
[(x1,x2),(y1,y2)]
Use a zip and unpacking operator.
>>> l = [['x1','y1'], ['x2','y2']]
>>> zip(*l)
[('x1', 'x2'), ('y1', 'y2')]
Handled more case in give test case.
If there are items in list which have different length.
In [19]: a
Out[19]: [[1, 2], [3, 4], [5, 6], [7, 8, 9]]
In [20]: import itertools
In [21]: b = itertools.izip_longest(*a)
In [22]: list(b)
Out[22]: [(1, 3, 5, 7), (2, 4, 6, 8), (None, None, None, 9)]
I have one array pat=[1,2,3,4,5,6,7] and a second array count=[5,6,7,8,9,10,11]. Is there a way without using dictionaries to get the following array newarray=[[1,5],[2,6],[3,7],[4,8],[5,9],[6,10],[7,11]]?
You can just zip the lists
>>> pat=[1,2,3,4,5,6,7]
>>> count=[5,6,7,8,9,10,11]
>>> list(zip(pat,count))
[(1, 5), (2, 6), (3, 7), (4, 8), (5, 9), (6, 10), (7, 11)]
Or if you want lists instead of tuples
>>> [[i,j] for i,j in zip(pat,count)]
[[1, 5], [2, 6], [3, 7], [4, 8], [5, 9], [6, 10], [7, 11]]
If you want inner elements to be list, you can use -
>>> pat=[1,2,3,4,5,6,7]
>>> count=[5,6,7,8,9,10,11]
>>> newarray = list(map(list,zip(pat,count)))
>>> newarray
[[1, 5], [2, 6], [3, 7], [4, 8], [5, 9], [6, 10], [7, 11]]
This first zips the two lists, combining the ith element of each list, then converts them into lists using map function, and later converts the complete outer map object (that we get from map function) into list
Without using zip, you can do the following:
def map_lists(l1, l2):
merged_list = []
for i in range(len(l1)):
merged_list.append([l1[i], l2[i]])
return merged_list
Or, the equivalent, using a list comprehension instead:
def map_lists(l1, l2):
return [[l1[i], l2[i]] for i in range(len(l1))]
I have a list whose nested list's size may vary with the multiple of 2. Currently, in this example, the nested list's length is 4.
a_list = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
According to length, I am trying to break the list to get the following result in the best possible pythonic way:
a = [[1,2], [5,6], [9,10]]
b = [[3,4], [7,8], [11,12]]
and if nested list's length is 6, then
c = [[..], [..], [..]]
Its kind of a transpose of a nested list but with sets of 2 values in a single row not to be transposed.
Using list comprehension:
>>> a_list = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
>>> a = [x[:2] for x in a_list]
>>> b = [x[2:] for x in a_list]
>>> a
[[1, 2], [5, 6], [9, 10]]
>>> b
[[3, 4], [7, 8], [11, 12]]
More general solution:
>>> [[x[i:i+2] for x in a_list] for i in range(0, len(a_list[0]), 2)]
[[[1, 2], [5, 6], [9, 10]],
[[3, 4], [7, 8], [11, 12]]]
I'd hesitate to call this "pythonic", since it's pretty much illegible, but:
>>> a, b = zip(*(zip(*[iter(s)]*2) for s in a_list))
>>> a
((1, 2), (5, 6), (9, 10))
>>> b
((3, 4), (7, 8), (11, 12))
Also works for 6-item lists:
>>> a_list = [[1,2,3,4,100,102],[5,6,7,8,103,104],[9,10,11,12,105,106]]
>>> a, b, c = zip(*(zip(*[iter(s)]*2) for s in a_list))
>>> a
((1, 2), (5, 6), (9, 10))
>>> b
((3, 4), (7, 8), (11, 12))
>>> c
((100, 102), (103, 104), (105, 106))
Almost the same as falsetru's answer, but first the nested lists are split into chunks of size 2 and then all of them are zipped together.
>>> a_list = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
>>> zip(*([j[i*2: i*2 + 2] for i in range(len(j) / 2)] for j in a_list))
[([1, 2], [5, 6], [9, 10]), ([3, 4], [7, 8], [11, 12])]
>>> a_list = [[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12]]
>>> zip(*([j[i*2: i*2 + 2] for i in range(len(j) / 2)] for j in a_list))
[([1, 2], [7, 8]), ([3, 4], [9, 10]), ([5, 6], [11, 12])]
>>> a_list = [[1,2,3,4,100,102],[5,6,7,8,103,104],[9,10,11,12,105,106]]
>>> zip(*([j[i*2: i*2 + 2] for i in range(len(j) / 2)] for j in a_list))
[([1, 2], [5, 6], [9, 10]), ([3, 4], [7, 8], [11, 12]), ([100, 102], [103, 104], [105, 106])]
A Fast way is using numpy.hsplit :
>>> import numpy
>>> numpy.hsplit(numpy.array(a_list),2)
[array([[ 1, 2],[ 5, 6],[ 9, 10]]),array([[ 3, 4],[ 7, 8],[11, 12]])]
Since readability is pythonic, here's a simpler iterator-based solution (without the neat tricks that #Zero used to turn it into a one-liner):
First, an iterator that turns a list [1,2,3,4,5,6] into [(1, 2), (3, 4), (5, 6)].
def pairs(lst):
it=iter(lst)
return list(zip(it, it)) # Return a list of pairs drawn from the same iterator
The list a_list can be transformed into a list of such pair lists as follows:
a_list = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
pair_list = [ pairs(row) for row in a_list ]
Finally, we need to effectively transpose this list, making a list of the first pair/element from each sublist, another list of the second one, etc. A nice idiom for transposing a list is zip(*some_list). Let's use it to make the transformation requested by the OP:
a, b = zip(*pair_list)
or to collect any number of generated lists in one list:
results = list( zip(*pair_list) )
Feel free to pack these into a one-liner (though I wouldn't):
results = list(zip( *(pairs(row) for row in a_list) ))
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]]