Python already sorts numbers numerically. If you want lexigraphic sort, you'd need to convert numbers to strings.
Easiest way to sort by multiple columns is by employing the fact that Python guarantees sorts are stable - which means order of elements is kept in case they are tied in regards to sorting key. Using that, you can sort from least significant to most significant key, resulting in expected output:
res = sorted(
sorted(
sorted(
sorted(arr, key = lambda x: x[3]),
key = lambda x: x[2]),
key = lambda x: x[1]),
key = lambda x: x[0])
Output:
[96, 132, 122, 112]
[96, 132, 329, 114]
[130, 175, 75, 152]
[130, 175, 182, 152]
[174, 218, 141, 196]
[174, 218, 328, 194]
[661, 701, 21, 683]
[707, 746, 375, 724]
[768, 806, 26, 788]
[768, 806, 286, 787]
[894, 933, 80, 914]
[894, 933, 166, 913]
[957, 998, 305, 980]
[957, 998, 394, 974]
Answer from matszwecja on Stack OverflowPython already sorts numbers numerically. If you want lexigraphic sort, you'd need to convert numbers to strings.
Easiest way to sort by multiple columns is by employing the fact that Python guarantees sorts are stable - which means order of elements is kept in case they are tied in regards to sorting key. Using that, you can sort from least significant to most significant key, resulting in expected output:
res = sorted(
sorted(
sorted(
sorted(arr, key = lambda x: x[3]),
key = lambda x: x[2]),
key = lambda x: x[1]),
key = lambda x: x[0])
Output:
[96, 132, 122, 112]
[96, 132, 329, 114]
[130, 175, 75, 152]
[130, 175, 182, 152]
[174, 218, 141, 196]
[174, 218, 328, 194]
[661, 701, 21, 683]
[707, 746, 375, 724]
[768, 806, 26, 788]
[768, 806, 286, 787]
[894, 933, 80, 914]
[894, 933, 166, 913]
[957, 998, 305, 980]
[957, 998, 394, 974]
Using argsort :
arr = np.array([[130, 175, 75, 152],
[96, 132, 122, 112],
[174, 218, 141, 196],
[661, 701, 21, 683],
[707, 746, 375, 724],
[957, 998, 305, 980],
[768, 806, 26, 788],
[957, 998, 394, 974],
[768, 806, 286, 787],
[174, 218, 328, 194],
[894, 933, 80, 914],
[130, 175, 182, 152],
[96, 132, 329, 114],
[894, 933, 166, 913]])
sorted_arr = arr[arr[:, 0].argsort()]
print(sorted_arr)
outputs what you want.
Short explanation (more details here) is getting the sorted indices of the columns of your array using argsort() then use the argsort result as the row indices and assign the resulting array back to a, as follows.
If you want (as in your second point ?) sort it based on the second column, use sorted_arr = arr[arr[:, 1].argsort()] or with a set priority in your columns, look in the mentioned link you should find what you want.
python - How to sort multidimensional array by column? - Stack Overflow
python - Sorting a 2D numpy array by multiple axes - Stack Overflow
Sorting 2d Array
python - Sort numpy 2d array by multiple columns - Stack Overflow
Yes. The sorted built-in accepts a key argument:
sorted(li,key=lambda x: x[1])
Out[31]: [['Jason', 1], ['John', 2], ['Jim', 9]]
note that sorted returns a new list. If you want to sort in-place, use the .sort method of your list (which also, conveniently, accepts a key argument).
or alternatively,
from operator import itemgetter
sorted(li,key=itemgetter(1))
Out[33]: [['Jason', 1], ['John', 2], ['Jim', 9]]
Read more on the python wiki.
You can use the sorted method with a key.
sorted(a, key=lambda x : x[1])
Using lexsort:
import numpy as np
a = np.array([(3, 2), (6, 2), (3, 6), (3, 4), (5, 3)])
ind = np.lexsort((a[:,1],a[:,0]))
a[ind]
# array([[3, 2],
# [3, 4],
# [3, 6],
# [5, 3],
# [6, 2]])
a.ravel() returns a view if a is C_CONTIGUOUS. If that is true,
@ars's method, slightly modifed by using ravel instead of flatten, yields a nice way to sort a in-place:
a = np.array([(3, 2), (6, 2), (3, 6), (3, 4), (5, 3)])
dt = [('col1', a.dtype),('col2', a.dtype)]
assert a.flags['C_CONTIGUOUS']
b = a.ravel().view(dt)
b.sort(order=['col1','col2'])
Since b is a view of a, sorting b sorts a as well:
print(a)
# [[3 2]
# [3 4]
# [3 6]
# [5 3]
# [6 2]]
The title says "sorting 2D arrays". Although the questioner uses an (N,2)-shaped array, it's possible to generalize unutbu's solution to work with any (N,M) array, as that's what people might actually be looking for.
One could transpose the array and use slice notation with negative step to pass all the columns to lexsort in reversed order:
>>> import numpy as np
>>> a = np.random.randint(1, 6, (10, 3))
>>> a
array([[4, 2, 3],
[4, 2, 5],
[3, 5, 5],
[1, 5, 5],
[3, 2, 1],
[5, 2, 2],
[3, 2, 3],
[4, 3, 4],
[3, 4, 1],
[5, 3, 4]])
>>> a[np.lexsort(np.transpose(a)[::-1])]
array([[1, 5, 5],
[3, 2, 1],
[3, 2, 3],
[3, 4, 1],
[3, 5, 5],
[4, 2, 3],
[4, 2, 5],
[4, 3, 4],
[5, 2, 2],
[5, 3, 4]])
Numpy includes a native function for sub-sorting by columns, lexsort:
idx = np.lexsort((arr[:,0], arr[:,1]))
arr_sorted = arr[idx]
Alternatively, you can use pandas syntax if you're more familiar; this will have some memory/time overhead but should be small for < 1m rows:
arr = [
[5, 0],
[3, 1],
[7, 0],
[2, 1]
]
df = pd.DataFrame(data=arr).sort_values([1,0])
arr_sorted = df.to_numpy()
output (both):
array([[5, 0],
[7, 0],
[2, 1],
[3, 1]])
You can use np.lexsort to sort an array on multiple columns:
idx = np.lexsort((a[:,0], a[:,1]))
a[idx]
Output:
array([[5, 0],
[7, 0],
[2, 1],
[3, 1]])
Transpose using zip(*l) to get a list of columns, then sort each individual column, then transpose back:
list(zip(*(sorted(col) for col in zip(*initial_table))))
Step by step output:
print(list(zip(*initial_table)))
# [(1, 5, 2), (2, 4, 3), (3, 3, 4)]
print([sorted(l) for l in zip(*initial_table)])
# [[1, 2, 5], [2, 3, 4], [3, 3, 4]]
print(list(zip(*(sorted(col) for col in zip(*initial_table)))))
# [(1, 2, 3), (2, 3, 3), (5, 4, 4)]
numpy is your friend!
import numpy as np
initial_table = [
[1, 2, 3],
[5, 4, 3],
[2, 3, 4]
]
np.sort(np.array(initial_table), axis=0)
>> array([[1, 2, 3],
[2, 3, 3],
[5, 4, 4]])