2

Consider the 3d numpy array arr:

[[[ 0,  9,  0,  2], [ 6,  8,  0,  2]],
 [[ 0,  9,  1,  5], [ 4,  8,  1,  5]],
 [[ 1,  0,  1,  2], [ 6,  6,  1,  2]],
 [[ 0,  9,  1,  5], [ 5,  5,  1,  5]],
 [[ 0,  9,  1,  5], [ 6,  5,  1,  5]],
 [[ 1,  0,  1,  2], [ 4,  7,  1,  2]],  
 [[ 0,  9,  3,  4], [ 6,  4,  3,  4]]])

I want to create a new array, new_arr, of the same shape by resorting arr as follows:

Sort by arr[:, 0, 0], then arr[:, 1, 0], then arr[:, 0, 1], then arr[:, 1, 1], etc.

The 2d arrays themselves are unchanged, but they are presented in a different (lexicographic) order within the 3d array.

The desired result is:

new_arr =  np.array(
[[[ 0,  9,  1,  5], [ 4,  8,  1,  5]],
 [[ 0,  9,  1,  5], [ 5,  5,  1,  5]],
 [[ 0,  9,  3,  4], [ 6,  4,  3,  4]],
 [[ 0,  9,  1,  5], [ 6,  5,  1,  5]],
 [[ 0,  9,  0,  2], [ 6,  8,  0,  2]], 
 [[ 1,  0,  1,  2], [ 4,  7,  1,  2]], 
 [[ 1,  0,  1,  2], [ 6,  6,  1,  2]]])
1
  • Added answer using numpy.lexsort Commented Jun 26 at 2:31

3 Answers 3

2

You can do it like this:

import numpy as np
arr=np.array([[[ 0,  9,  0,  2], [ 6,  8,  0,  2]],
 [[ 0,  9,  1,  5], [ 4,  8,  1,  5]],
 [[ 1,  0,  1,  2], [ 6,  6,  1,  2]],
 [[ 0,  9,  1,  5], [ 5,  5,  1,  5]],
 [[ 0,  9,  1,  5], [ 6,  5,  1,  5]],
 [[ 1,  0,  1,  2], [ 4,  7,  1,  2]],  
 [[ 0,  9,  3,  4], [ 6,  4,  3,  4]]])
new_arr=list(arr)
new_arr.sort(key=lambda x:[x[0][0],x[1][0],x[0][1],x[1][1]])
new_arr=np.array(new_arr)
print(new_arr)
Sign up to request clarification or add additional context in comments.

Comments

1

Another method include:

import numpy as np

rule = [0,0],[1,0],[0,1],[1,1]
new_arr[np.lexsort(np.fliplr(new_arr[:,*np.array(rule).T]).T)]

You could also simply do:

new_arr[np.lexsort(np.fliplr(new_arr[:,[0,1,0,1],[0,0,1,1]]).T)]

2 Comments

So [0,0] is the primary key but it's passed last to lexsort. Still don't get why but guess it's a numpy internal stuff.
According to documentation, if you are sorting by a and breaking the ties by b then you use lexsort((b,a)) and not lexsort((a, b)). ie the key starts from last to the firs. In this case, I first sort using 0,0,1,1 then 0,1,0,1
0

Using numpy.lexsort and specifying keys in reverse order and formatted as requested by OP.

import numpy as np

new_arr = np.array([[[ 0,  9,  0,  2], [ 6,  8,  0,  2]],
 [[ 0,  9,  1,  5], [ 4,  8,  1,  5]],
 [[ 1,  0,  1,  2], [ 6,  6,  1,  2]],
 [[ 0,  9,  1,  5], [ 5,  5,  1,  5]],
 [[ 0,  9,  1,  5], [ 6,  5,  1,  5]],
 [[ 1,  0,  1,  2], [ 4,  7,  1,  2]],  
 [[ 0,  9,  3,  4], [ 6,  4,  3,  4]]])

keys = (new_arr[:,1,1], new_arr[:, 0, 1], new_arr[:,1,0], new_arr[:,0,0])
sorted_indices = np.lexsort(keys)

arr = new_arr[sorted_indices]
print(arr)
[[[0 9 1 5] [4 8 1 5]]
 [[0 9 1 5] [5 5 1 5]]
 [[0 9 3 4] [6 4 3 4]]
 [[0 9 1 5] [6 5 1 5]]
 [[0 9 0 2] [6 8 0 2]]
 [[1 0 1 2] [4 7 1 2]]
 [[1 0 1 2] [6 6 1 2]]]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.