How to unpack tuples in nested list? - python

I'm having trouble unpacking a 2-dimensional list of tuples (or rather, I'm looking for a more elegant solution).
The list is as shown:
a = [ [(2, 3, 5), (3, 4, 6), (4, 5, 7), (1, 1, 1), (1, 2, 3)],
[(4, 9, 2), (8, 8, 0), (3, 5, 1), (2, 6, 8), (2, 4, 8)],
[(8, 7, 5), (2, 5, 1), (9, 2, 2), (4, 5, 1), (0, 1, 9)], ...]
And I want to unpack the tuples to obtain 3 nested lists of the same form, i.e.:
a_r = [ [2, 3, 4, 1, 1] , [4, 8, 3, 2, 2] , [8, 2, 9, 4, 0] , ...]
a_g = [ [3, 4, 5, 1, 2] , [9, 8, 5, 6, 4] , [7, 5, 2, 5, 1] , ...]
and so on. Here is my code:
a_r = []
a_g = []
a_b = []
for i in xrange(len(a)):
r0=[]
g0=[]
b0=[]
for j in range(5):
r0.append(a[i][j][0])
g0.append(a[i][j][1])
b0.append(a[i][j][2])
a_r.append(r0)
a_g.append(g0)
a_b.append(b0)
I'm sure there are more efficient ways to do this (I've just begun learning Python). This question is similar, but I wasn't able to follow the functional programming.
Thanks!

I think you are after something like this:
a = [ [(2, 3, 5), (3, 4, 6), (4, 5, 7), (1, 1, 1), (1, 2, 3)],
[(4, 9, 2), (8, 8, 0), (3, 5, 1), (2, 6, 8), (2, 4, 8)],
[(8, 7, 5), (2, 5, 1), (9, 2, 2), (4, 5, 1), (0, 1, 9)]]
for row in a:
print(list(zip(*row)))
Which gives:
[(2, 3, 4, 1, 1), (3, 4, 5, 1, 2), (5, 6, 7, 1, 3)]
[(4, 8, 3, 2, 2), (9, 8, 5, 6, 4), (2, 0, 1, 8, 8)]
[(8, 2, 9, 4, 0), (7, 5, 2, 5, 1), (5, 1, 2, 1, 9)]
The resulting tuples are same as in your example, but different order. I dont understand how you ordered them. If you could clarify this, I might modify the example.
Hope this helps.

>>> a = [ [(2, 3, 5), (3, 4, 6), (4, 5, 7), (1, 1, 1), (1, 2, 3)],
... [(4, 9, 2), (8, 8, 0), (3, 5, 1), (2, 6, 8), (2, 4, 8)],
... [(8, 7, 5), (2, 5, 1), (9, 2, 2), (4, 5, 1), (0, 1, 9)]]
>>> zip(*(zip(*x) for x in a))
[((2, 3, 4, 1, 1), (4, 8, 3, 2, 2), (8, 2, 9, 4, 0)), ((3, 4, 5, 1, 2), (9, 8, 5, 6, 4), (7, 5, 2, 5, 1)), ((5, 6, 7, 1, 3), (2, 0, 1, 8, 8), (5, 1, 2, 1, 9))]
>>> for row in _:
... print row
...
((2, 3, 4, 1, 1), (4, 8, 3, 2, 2), (8, 2, 9, 4, 0))
((3, 4, 5, 1, 2), (9, 8, 5, 6, 4), (7, 5, 2, 5, 1))
((5, 6, 7, 1, 3), (2, 0, 1, 8, 8), (5, 1, 2, 1, 9))
If it must be lists
>>> map(list, zip(*(map(list, zip(*x)) for x in a)))
[[[2, 3, 4, 1, 1], [4, 8, 3, 2, 2], [8, 2, 9, 4, 0]], [[3, 4, 5, 1, 2], [9, 8, 5, 6, 4], [7, 5, 2, 5, 1]], [[5, 6, 7, 1, 3], [2, 0, 1, 8, 8], [5, 1, 2, 1, 9]]]
>>> for row in _:
... print row
...
[[2, 3, 4, 1, 1], [4, 8, 3, 2, 2], [8, 2, 9, 4, 0]]
[[3, 4, 5, 1, 2], [9, 8, 5, 6, 4], [7, 5, 2, 5, 1]]
[[5, 6, 7, 1, 3], [2, 0, 1, 8, 8], [5, 1, 2, 1, 9]]

Tuples are immutable (meaning you cannot change them), so you're going to have to go through every element to extract them. That is essentially what the functional programming example you linked to is doing, in a very pythonic, list comprehension, way.
To help you help yourself, as shirdharama says, take a look at the example again and know that fmap_lol really means "function mapping - list of lists", fmap_list means "function mapping - list", and fmap_el means "function mapping - element". So split_nt calls fmap_lol, which splits your input in a list of lists (the tuples), calls fmap_list, which takes each list and calls fmap_el, which returns the element back up the chain.
The example is just a way to walk through the tuples to extract every element and put them where you wish. It's functional because they are functions calls, not a single line of later forgotten gobbligook.
If you're unfamiliar with list comprehensions, lamda (or anonymous functions), or anything else in the example I suggest spending some time with the python documentation and looking each up.

Related

How can i combine these two into one list comprehension?

How can I combine these two into one list comprehension? Thank you.
transactions = [[2, 8, 3, 6, 1, 9], [0, 5, 9], [0, 9], [4, 7, 0, 5, 9],
[8, 3], [1, 6, 3, 8], [9, 0, 5], [3, 8], [5, 7, 0, 4], [3, 1, 2, 6, 0]]
code1
new_transaction= []
for num in transactions:
num = sorted(num)
new_transaction.append(num)
new_transaction
code2
product_pairs = [[(num[i],num[j]) for i in range(len(num)) for j in range(i+1, len(num))]for num in new_transaction]
print(product_pairs)
expected output:
[[(1, 2), (1, 3), (1, 6), (1, 8), (1, 9), (2, 3), (2, 6), (2, 8), (2, 9), (3, 6), (3, 8), (3, 9), (6, 8), (6, 9), (8, 9)], [(0, 5), (0, 9), (5, 9)], [(0, 9)], [(0, 4), (0, 5), (0, 7), (0, 9), (4, 5), (4, 7), (4, 9), (5, 7), (5, 9), (7, 9)], [(3, 8)], [(1, 3), (1, 6), (1, 8), (3, 6), (3, 8), (6, 8)], [(0, 5), (0, 9), (5, 9)], [(3, 8)], [(0, 4), (0, 5), (0, 7), (4, 5), (4, 7), (5, 7)], [(0, 1), (0, 2), (0, 3), (0, 6), (1, 2), (1, 3), (1, 6), (2, 3), (2, 6), (3, 6)]]
You can combine these two like this.
transactions = [[2, 8, 3, 6, 1, 9], [0, 5, 9], [0, 9], [4, 7, 0, 5, 9], [8, 3], [1, 6, 3, 8], [9, 0, 5], [3, 8], [5, 7, 0, 4], [3, 1, 2, 6, 0]]
product_pairs = [[(num[i],num[j]) for i in range(len(num)) for j in range(i+1, len(num))]for num in [sorted(num) for num in transactions]]
print(product_pairs)
This code returns the same output.
from itertools import combinations
transactions = [[2, 8, 3, 6, 1, 9], [0, 5, 9], [0, 9], [4, 7, 0, 5, 9], [8, 3], [1, 6, 3, 8], [9, 0, 5], [3, 8], [5, 7, 0, 4], [3, 1, 2, 6, 0]]
[a.sort() for a in transactions]
product_pairs = [list(combinations(a,2)) for a in transactions]
print(product_pairs)

Combination of List and Nested List by Index

The output of my script is a list and a nested list. I would like to get the combinations of the two lists by index. In this instance, I have the following two lists:
x = [0, 1, 2, 3]
y = [[0, 1, 2, 3],
[0, 1, 2, 3, 4, 5, 6, 7, 8],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4, 5, 6, 7, 8]]
The desired output should look something like this.
[(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1,
7), (1, 8), (2, 0), (2, 1), (2, 2), (2, 3), (2, 4), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5),
(3, 6), (3, 7), (3, 8)]
I've looked at many posts about itertools.combinations and itertools.product, but I cannot find anything about looping and combining at the same time, which I think would be the approach to the problem. I want to get all combinations x[0] and y[0], then x[1] and y[1], etc.
You can do this with a list comprehension.
x = [0, 1, 2, 3]
y = [[0, 1, 2, 3],
[0, 1, 2, 3, 4, 5, 6, 7, 8],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4, 5, 6, 7, 8]]
final = [(i,j) for i in x for j in y[i]]
It seems you are going to do the catidion multiplication of two array. Here is the reference check and let me know if worked for you.
Cartesian product of x and y array points into single array of 2D points

Set of enumerate items in list in Python [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I need to create a lot of sets of numbers. I add my output and the output that I need.
I wrote the first item output of my list, then I need the same for all items.
a = [1, 2, 3, 4, 5, 6, 7, 8]
for index, item in enumerate(a):
index_0 = index
index_1 = index + 1
index_2 = index + 2
index_3 = index + 3
print((a[index_0], a[index_1], a[index_2], a[index_3]))
>>>
1, 2, 3, 4
2, 3, 4, 5
3, 4, 5, 6
4, 5, 6, 7
5, 6, 7, 8
What I'm looking for for each item:
1,2,3,4
1,2,3,5
1,2,3,6
1,2,3,7
1,2,3,8
1,2,4,5
1,2,4,6
1,2,4,7
1,2,4,8
1,2,5,6
1,2,5,7
1,2,5,8
1,2,6,7
1,2,6,8
1,2,7,8
1,3,4,5
1,3,4,6
1,3,4,7
1,3,4,8
1,3,5,6
1,3,5,7
1,3,5,8
1,3,6,7
1,3,6,8
1,3,7,8
1,4,5,6
1,4,5,7
1,4,5,8
1,4,6,7
1,4,6,8
1,4,7,8
1,5,6,7
1,5,7,8
1,6,7,8
Are you looking to use itertools combinations:
from itertools import combinations
list(combinations([1,2,3,4,5,6,7,8], 4))
Output:
[(1, 2, 3, 4),
(1, 2, 3, 5),
(1, 2, 3, 6),
(1, 2, 3, 7),
(1, 2, 3, 8),
(1, 2, 4, 5),
(1, 2, 4, 6),
(1, 2, 4, 7),
(1, 2, 4, 8),
(1, 2, 5, 6),
(1, 2, 5, 7),
(1, 2, 5, 8),
(1, 2, 6, 7),
(1, 2, 6, 8),
(1, 2, 7, 8),
(1, 3, 4, 5),
(1, 3, 4, 6),
(1, 3, 4, 7),
(1, 3, 4, 8),
(1, 3, 5, 6),
(1, 3, 5, 7),
(1, 3, 5, 8),
(1, 3, 6, 7),
(1, 3, 6, 8),
(1, 3, 7, 8),
(1, 4, 5, 6),
(1, 4, 5, 7),
(1, 4, 5, 8),
(1, 4, 6, 7),
(1, 4, 6, 8),
(1, 4, 7, 8),
(1, 5, 6, 7),
(1, 5, 6, 8),
(1, 5, 7, 8),
(1, 6, 7, 8),
(2, 3, 4, 5),
(2, 3, 4, 6),
(2, 3, 4, 7),
(2, 3, 4, 8),
(2, 3, 5, 6),
(2, 3, 5, 7),
(2, 3, 5, 8),
(2, 3, 6, 7),
(2, 3, 6, 8),
(2, 3, 7, 8),
(2, 4, 5, 6),
(2, 4, 5, 7),
(2, 4, 5, 8),
(2, 4, 6, 7),
(2, 4, 6, 8),
(2, 4, 7, 8),
(2, 5, 6, 7),
(2, 5, 6, 8),
(2, 5, 7, 8),
(2, 6, 7, 8),
(3, 4, 5, 6),
(3, 4, 5, 7),
(3, 4, 5, 8),
(3, 4, 6, 7),
(3, 4, 6, 8),
(3, 4, 7, 8),
(3, 5, 6, 7),
(3, 5, 6, 8),
(3, 5, 7, 8),
(3, 6, 7, 8),
(4, 5, 6, 7),
(4, 5, 6, 8),
(4, 5, 7, 8),
(4, 6, 7, 8),
(5, 6, 7, 8)]

Converting list of points to list of tuples in python

I've just written some code to convert a list of points into a list of to/from tuples but it doesn't feel very efficient.
I was wondering if anyone had any suggestions to make this more concise?
from_point, to_point = None, None
point_list = []
for p in [1, 5, 2, 4, 7, 9]:
to_point = p
if from_point and to_point:
point_list.append((from_point, to_point))
from_point = to_point
print(point_list)
Input: [1, 5, 2, 4, 7, 9]
Output: [(1, 5), (5, 2), (2, 4), (4, 7), (7, 9)]
Edit: Changed points to be non sequential.
You can always use zip:
>>> p = [1, 5, 2, 4, 7, 9]
>>> point_list = list(zip(p[:-1], p[1:]))
>>> print(point_list)
[(1, 5), (5, 2), (2, 4), (4, 7), (7, 9)]
An alternative one line solution
input = [1, 2, 3, 4, 5, 6]
output = [(input[index], input[index+1]) for index in range(len(list)-1)]
print(output)
What about this?
x=[1, 5, 2, 4, 7, 9]
print [ tuple(x[i:i+2]) for i in xrange(len(x)-1) ]
Using more_itertools:
import more_itertools as mit
list(mit.pairwise([1, 5, 2, 4, 7, 9]))
# [(1, 5), (5, 2), (2, 4), (4, 7), (7, 9)]

numpy.searchsorted with more than one source

Let's say that I have two arrays in the form
a = [0, 0, 1, 1, 2, 3, 3, 3, 4, 4, 5, 6]
b = [1, 2, 1, 2, 1, 4, 7, 9, 4, 8, 1, 1]
As you can see, the above arrays are sorted, when considered a and b as columns of a super array.
Now, I want to do a searchsorted on this array. For instance, if I search for (3, 7) (a = 3 and b = 7), I should get 6.
Whenever there are duplicate values in a, the search should continue with values in b.
Is there a built-in numpy method to do it? Or what could be the efficient way to do it, assuming that I have million entries in my array.
I tried with numpy.recarray, to create one recarray with a and b and tried searching in it, but I am getting the following error.
TypeError: expected a readable buffer object
Any help is much appreciated.
You're almost there. It's just that numpy.record (which is what I assume you used, given the error message you received) isn't really what you want; just create a one-item record array:
>>> a_b = numpy.rec.fromarrays((a, b))
>>> a_b
rec.array([(0, 1), (0, 2), (1, 1), (1, 2), (2, 1), (3, 4), (3, 7), (3, 9),
(4, 4), (4, 8), (5, 1), (6, 1)],
dtype=[('f0', '<i8'), ('f1', '<i8')])
>>> numpy.searchsorted(a_b, numpy.array((3, 7), dtype=a_b.dtype))
6
It might also be useful to know that sort and argsort sort record arrays lexically, and there is also lexsort. An example using lexsort:
>>> random_idx = numpy.random.permutation(range(12))
>>> a = numpy.array(a)[random_idx]
>>> b = numpy.array(b)[random_idx]
>>> sorted_idx = numpy.lexsort((b, a))
>>> a[sorted_idx]
array([0, 0, 1, 1, 2, 3, 3, 3, 4, 4, 5, 6])
>>> b[sorted_idx]
array([1, 2, 1, 2, 1, 4, 7, 9, 4, 8, 1, 1])
Sorting record arrays:
>>> a_b = numpy.rec.fromarrays((a, b))
>>> a_b[a_b.argsort()]
rec.array([(0, 1), (0, 2), (1, 1), (1, 2), (2, 1), (3, 4), (3, 7), (3, 9),
(4, 4), (4, 8), (5, 1), (6, 1)],
dtype=[('f0', '<i8'), ('f1', '<i8')])
>>> a_b.sort()
>>> a_b
rec.array([(0, 1), (0, 2), (1, 1), (1, 2), (2, 1), (3, 4), (3, 7), (3, 9),
(4, 4), (4, 8), (5, 1), (6, 1)],
dtype=[('f0', '<i8'), ('f1', '<i8')])
You could use a repeated searchsorted from left and right:
left, right = np.searchsorted(a, 3, side='left'), np.searchsorted(a, 3, side='right')
index = left + np.searchsorted(b[left:right], 7)
This works for me:
>>> a = [0, 0, 1, 1, 2, 3, 3, 3, 4, 4, 5, 6]
>>> b = [1, 2, 1, 2, 1, 4, 7, 9, 4, 8, 1, 1]
>>> Z = numpy.array(zip(a, b), dtype=[('a','int'), ('b','int')])
>>> Z.searchsorted(numpy.asarray((3,7), dtype=Z.dtype))
6
I think the trick might be to make sure the argument to searchsorted has the same dtype as the array. When I try Z.searchsorted((3, 7)) I get a segfault.
Here's an interesting way to do it (though it's not the most efficient way, as I believe it's O(n) rather than O(log(n)) as ecatmur's answer would be; it is, however, more compact):
np.searchsorted(a + 1j*b, a_val + 1j*b_val)
Example:
>>> a = np.array([0, 0, 1, 1, 2, 3, 3, 3, 4, 4, 5, 6])
>>> b = np.array([1, 2, 1, 2, 1, 4, 7, 9, 4, 8, 1, 1])
>>> np.searchsorted(a + 1j*b, 4 + 1j*8)
9
n arrays extension :
import numpy as np
def searchsorted_multi(*args):
v = args[-1]
if len(v) != len(args[:-1]):
raise ValueError
l, r = 0, len(args[0])
ind = 0
for vi, ai in zip(v, args[:-1]):
l, r = [np.searchsorted(ai[l:r], vi, side) for side in ('left', 'right')]
ind += l
return ind
if __name__ == "__main__":
a = [0, 0, 1, 1, 2, 3, 3, 3, 4, 4, 5, 6]
b = [1, 2, 1, 2, 1, 4, 7, 9, 4, 8, 1, 1]
c = [1, 2, 1, 2, 1, 4, 7, 9, 4, 8, 1, 2]
assert(searchsorted_multi(a, b, (3, 7)) == 6)
assert(searchsorted_multi(a, b, (3, 0)) == 5)
assert(searchsorted_multi(a, b, c, (6, 1, 2)) == 12)
Or without numpy:
>>> import bisect
>>> a = [0, 0, 1, 1, 2, 3, 3, 3, 4, 4, 5, 6]
>>> b = [1, 2, 1, 2, 1, 4, 7, 9, 4, 8, 1, 1]
>>> bisect.bisect_left(zip(a,b), (3,7))
6

Categories