Get second minimum values per column in 2D array Get second minimum values per column in 2D array arrays arrays

Get second minimum values per column in 2D array


Try this, in just one line:

[sorted(i)[1] for i in zip(*A)]

in action:

In [12]: A = [[72, 76, 44, 62, 81, 31],     ...:      [54 ,36 ,82 ,71 ,40, 45],     ...:      [63 ,59, 84, 36, 34 ,51],     ...:      [58, 53, 59, 22, 77 ,64],     ...:      [35 ,77, 60, 76, 57, 44]] In [18]: [sorted(i)[1] for i in zip(*A)]                                                                                                                                                                           Out[18]: [54, 53, 59, 36, 40, 44]

zip(*A) will transpose your list of list so the columns become rows.

and if you have duplicate value, for example:

In [19]: A = [[72, 76, 44, 62, 81, 31],     ...:  [54 ,36 ,82 ,71 ,40, 45],     ...:  [63 ,59, 84, 36, 34 ,51],     ...:  [35, 53, 59, 22, 77 ,64],   # 35    ...:  [35 ,77, 50, 76, 57, 44],]  # 35

If you need to skip both 35s, you can use set():

In [29]: [sorted(list(set(i)))[1] for i in zip(*A)]                                                                                                                                                                Out[29]: [54, 53, 50, 36, 40, 44]


Operations on numpy arrays should be done with numpy functions, so look at this one:

np.sort(A, axis=0)[1, :]
Out[61]: array([54, 53, 59, 36, 40, 44])


you can use heapq.nsmallest

from heapq import nsmallest[nsmallest(2, e)[-1] for e in zip(*A)]

output:

[54, 53, 50, 36, 40, 44]

I added a simple benchmark to compare the performance of the different solutions already posted:

enter image description here

from simple_benchmark import BenchmarkBuilderfrom heapq import nsmallestb = BenchmarkBuilder()@b.add_function()def MehrdadPedramfar(A):    return [sorted(i)[1] for i in zip(*A)]@b.add_function()def NicolasGervais(A):    return np.sort(A, axis=0)[1, :]@b.add_function()def imcrazeegamerr(A):    rotated = zip(*A[::-1])    result = []    for arr in rotated:        # sort each 1d array from min to max        arr = sorted(list(arr))        # add the second minimum value to result array        result.append(arr[1])    return result@b.add_function()def Daweo(A):    return np.apply_along_axis(lambda x:heapq.nsmallest(2,x)[-1], 0, A)@b.add_function()       def kederrac(A):    return [nsmallest(2, e)[-1] for e in zip(*A)]@b.add_arguments('Number of row/cols (A is  square matrix)')def argument_provider():    for exp in range(2, 18):        size = 2**exp        yield size, [[randint(0, 1000) for _ in range(size)] for _ in range(size)]r = b.run()r.plot()

Using zip with sorted function is the fastest solution for small 2d lists while using zip with heapq.nsmallest shows to be the best on big 2d lists