I would like to be able to generate all unique permutations of a 2d array in python and keep the order.
Let's say I have a 2D matrix [[1, 2, 3], [4, 5, 6]]. Expected result should be a in 8 x 3 in the form
[[1, 2, 3],
[1, 2, 6],
[1, 5, 3],
[1, 5, 6],
[4, 2, 3],
[4, 2, 6],
[4, 5, 3],
[4, 5, 6]].
Thanks
Transpose the array, and then use itertools.product:
from itertools import product
list(map(list, product(*zip(*data))))
This outputs:
[[1, 2, 3], [1, 2, 6], [1, 5, 3], [1, 5, 6], [4, 2, 3], [4, 2, 6], [4, 5, 3], [4, 5, 6]]
The itertools method with product would be the most readible way to do this, but since your question is tagged numpy, here is how you can do this using only Numpy methods.
1. Permutations without expected order
You can use this method if order is not important for you. This uses np.meshgrid and np.stack with some .reshape to get the permutations you need, minus the order you expect.
import numpy as np
lst = [[1, 2, 3], [4, 5, 6]]
arr = np.array(lst)
np.stack(np.meshgrid(*arr.T),-1).reshape(-1,3)
array([[1, 2, 3],
[1, 2, 6],
[4, 2, 3],
[4, 2, 6],
[1, 5, 3],
[1, 5, 6],
[4, 5, 3],
[4, 5, 6]])
2. Permutations with expected order
Getting the order to work is a bit "hacky" but a small modification over the above array with simple reordering of columns can solve this with pretty much the same code.
import numpy as np
lst = [[1, 2, 3], [4, 5, 6]]
order = [1,0,2]
arr = np.array(lst)[:,order]
np.stack(np.meshgrid(*arr.T),-1).reshape(-1,3)[:,order]
array([[1, 2, 3],
[1, 2, 6],
[1, 5, 3],
[1, 5, 6],
[4, 2, 3],
[4, 2, 6],
[4, 5, 3],
[4, 5, 6]])
Related
Suppose I have a list of lists like this:
list = [[1, 2, 3],
[4, 5, 6, 7],
[3, 4]]
I wish to create a 2-d array like this using the above input in Python:
result = [[1,4,3],[1,4,4],[1,5,3],[1,5,4],[1,6,3],[1,6,4],[1,7,3],[1,7,4],
[2,4,3],[2,4,4],[2,5,3],[2,5,4],[2,6,3],[2,6,4],[2,7,3],[2,7,4],
[3,4,3],[3,4,4],[3,5,3],[3,5,4],[3,6,3],[3,6,4],[3,7,3],[3,7,4]]
This is kind of a truth table.
Note - The length of list can vary (it can contain more lists) and also the length of inner lists can vary.
You can use itertools.product(). l is your original list (avoid using "list" as name, due to the existing built-in data structure in python)
res=[list(i) for i in itertools.product(*l)]
>>> print(res)
[[1, 4, 3], [1, 4, 4], [1, 5, 3], [1, 5, 4], [1, 6, 3], [1, 6, 4], [1, 7, 3], [1, 7, 4], [2, 4, 3], [2, 4, 4], [2, 5, 3], [2, 5, 4], [2, 6, 3], [2, 6, 4], [2, 7, 3], [2, 7, 4], [3, 4, 3], [3, 4, 4], [3, 5, 3], [3, 5, 4], [3, 6, 3], [3, 6, 4], [3, 7, 3], [3, 7, 4]]
So I have a Numpy Array with a bunch of numpy arrays inside of them. I want to group them based on the position in their individual array.
For Example:
If Matrix is:
[[1, 2], [2, 3], [4, 5], [6, 7]]
Then the code should return:
[[1, 2, 4, 6], [2, 3, 5, 7]]
This is becuase 1, 2, 4, 6 are all the first elements in their individual arrays, and 2, 3, 5, 7 are the second elements in their individual arrays.
Anyone know some function that could do this. Thanks.
Answer in Python.
Using numpy transpose should do the trick:
a = np.array([[1, 2], [2, 3], [4, 5], [6, 7]])
a_t = a.T
print(a_t)
array([[1, 2, 4, 6],
[2, 3, 5, 7]])
Your data as a list:
In [101]: alist = [[1, 2], [2, 3], [4, 5], [6, 7]]
In [102]: alist
Out[102]: [[1, 2], [2, 3], [4, 5], [6, 7]]
and as a numpy array:
In [103]: arr = np.array(alist)
In [104]: arr
Out[104]:
array([[1, 2],
[2, 3],
[4, 5],
[6, 7]])
A standard idiom for 'transposing' lists is:
In [105]: list(zip(*alist))
Out[105]: [(1, 2, 4, 6), (2, 3, 5, 7)]
with arrays, there's a transpose method:
In [106]: arr.transpose()
Out[106]:
array([[1, 2, 4, 6],
[2, 3, 5, 7]])
The first array is (4,2) shape; its transpose is (2,4).
I have a nested list as follows:
A = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
I need to permute only the elements inside each list.
do you have any idea how can I do this?
You can do something like this:
import random
A = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
for x in A:
random.shuffle(x)
To shuffle each sublist in a list comprehension, you cannot use random.shuffle because it works in place. You can use random.sample with the sample length = the length of the list:
import random
A = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
new_a = [random.sample(l,len(l)) for l in A]
print(new_a)
an output:
[[2, 1, 3], [5, 4, 6], [7, 9, 8]]
That solution is the best one if you don't want to modify your original list. Else, using shuffle in a loop as someone else answered works fine as well.
Use permutations from itertools:
from itertools import permutations
A = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
out = []
for i in A:
for j in permutations(i):
out.append(list(j))
print out
OUTPUT:
[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1],
[4, 5, 6], [4, 6, 5], [5, 4, 6], [5, 6, 4], [6, 4, 5], [6, 5, 4],
[7, 8, 9], [7, 9, 8], [8, 7, 9], [8, 9, 7], [9, 7, 8], [9, 8, 7]]
I'd like to turn an open mesh returned by the numpy ix_ routine to a list of coordinates
eg, for:
In[1]: m = np.ix_([0, 2, 4], [1, 3])
In[2]: m
Out[2]:
(array([[0],
[2],
[4]]), array([[1, 3]]))
What I would like is:
([0, 1], [0, 3], [2, 1], [2, 3], [4, 1], [4, 3])
I'm pretty sure I could hack it together with some iterating, unpacking and zipping, but I'm sure there must be a smart numpy way of achieving this...
Approach #1 Use np.meshgrid and then stack -
r,c = np.meshgrid(*m)
out = np.column_stack((r.ravel('F'), c.ravel('F') ))
Approach #2 Alternatively, with np.array() and then transposing, reshaping -
np.array(np.meshgrid(*m)).T.reshape(-1,len(m))
For a generic case with for generic number of arrays used within np.ix_, here are the modifications needed -
p = np.r_[2:0:-1,3:len(m)+1,0]
out = np.array(np.meshgrid(*m)).transpose(p).reshape(-1,len(m))
Sample runs -
Two arrays case :
In [376]: m = np.ix_([0, 2, 4], [1, 3])
In [377]: p = np.r_[2:0:-1,3:len(m)+1,0]
In [378]: np.array(np.meshgrid(*m)).transpose(p).reshape(-1,len(m))
Out[378]:
array([[0, 1],
[0, 3],
[2, 1],
[2, 3],
[4, 1],
[4, 3]])
Three arrays case :
In [379]: m = np.ix_([0, 2, 4], [1, 3],[6,5,9])
In [380]: p = np.r_[2:0:-1,3:len(m)+1,0]
In [381]: np.array(np.meshgrid(*m)).transpose(p).reshape(-1,len(m))
Out[381]:
array([[0, 1, 6],
[0, 1, 5],
[0, 1, 9],
[0, 3, 6],
[0, 3, 5],
[0, 3, 9],
[2, 1, 6],
[2, 1, 5],
[2, 1, 9],
[2, 3, 6],
[2, 3, 5],
[2, 3, 9],
[4, 1, 6],
[4, 1, 5],
[4, 1, 9],
[4, 3, 6],
[4, 3, 5],
[4, 3, 9]])
I'm trying to find a way to fill an array with rows of values. It's much easier to express my desired output with an example. Given the input of an N x M matrix, array1,
array1 = np.array([[2, 3, 4],
[4, 8, 3],
[7, 6, 3]])
I would like to output an array of arrays in which each row is an N x N consisting of the values from the respective row. The output would be
[[[2, 3, 4],
[2, 3, 4],
[2, 3, 4]],
[[4, 8, 3],
[4, 8, 3],
[4, 8, 3]],
[[7, 6, 3],
[7, 6, 3],
[7, 6, 3]]]
You can reshape the array from 2d to 3d, then use numpy.repeat() along the desired axis:
np.repeat(array1[:, None, :], 3, axis=1)
#array([[[2, 3, 4],
# [2, 3, 4],
# [2, 3, 4]],
# [[4, 8, 3],
# [4, 8, 3],
# [4, 8, 3]],
# [[7, 6, 3],
# [7, 6, 3],
# [7, 6, 3]]])
Or equivalently you can use numpy.tile:
np.tile(array1[:, None, :], (1,3,1))
Another solution which is sometimes useful is the following
out = np.empty((3,3,3), dtype=array1.dtype)
out[...] = array1[:, None, :]