I have a python 2D list like this-
[[3,4],[1,2],[2,1],[6,5]]
I like to have it sorted in both direction, row and column-wise. So, my desired output would be like this-
[[1, 2], [1, 2], [3, 4], [5, 6]]
What I have done is-
list.sort(key = lambda x: (x[1], x[0]))
And what I am getting is-
[[2, 1], [1, 2], [3, 4], [6, 5]]
Can anyone please help to sort it in-place
with lambda
expression?
The key
parameter (and lambda
) is not meant to modify the content of the list
. Instead, it is meant to be used for sorting according to how each element evaluates when the key
function is applied.
However, you can use key
's side-effects to achieve what you are after by calling .sort()
on your key
's function's argument. Since .sort()
result is just None
, you also need to provide the statement itself to be used for the actual sorting:
l = [[3,4],[1,2],[2,1],[6,5]]
l.sort(key=lambda x: (x.sort(), x))
print(l)
# [[1, 2], [1, 2], [3, 4], [5, 6]]
This is not considered good programming practice, though.
A cleaner and much more efficient, but obviously not 1-line, the approach would be:
l = [[3,4],[1,2],[2,1],[6,5]]
for x in l:
x.sort()
l.sort()
print(l)
# [[1, 2], [1, 2], [3, 4], [5, 6]]
The key
based approach is also significantly less efficient since it tries to sort the inner lists at each key
call which we should expect to occur n log n
times, against the n
times strictly required, thus some of the inner lists is inevitably being sorted more than necessary. Instead, looping through the outer list explicitly sort each internal list once.
Just to give some ideas of the timings:
import random
import copy
import collections
def double_sort_loop(seq):
for x in seq:
x.sort()
seq.sort()
def double_sort_deque(seq):
collections.deque(map(lambda x: x.sort(), seq), maxlen=0)
seq.sort()
def double_sort_key(seq):
seq.sort(key=lambda x: (x.sort(), x))
def gen_input(n, m, v_min=None, v_max=None):
if v_min is None:
v_min = 0
if v_max is None:
v_max = v_min + (2 * m * n)
return [[random.randint(v_min, v_max) for _ in range(m)] for _ in range(n)]
random.seed(0)
base = gen_input(100000, 10)
%timeit seq = copy.deepcopy(base); double_sort_loop(seq)
# 1 loop, best of 3: 1.03 s per loop
%timeit seq = copy.deepcopy(base); double_sort_deque(seq)
# 1 loop, best of 3: 1.02 s per loop
%timeit seq = copy.deepcopy(base); double_sort_key(seq)
# 1 loop, best of 3: 1.19 s per loop