如何按值(从矩阵)对列表进行排序,并按第一个最小值,然后按第二个最小值等来断开关系。?

时间:2017-01-29 18:37:48

标签: python sorting

我们假设我有一个矩阵,其中每列与一个值相关联。例如:

A = [[ 7.41,  5.44,  4.75,  0.35,  6.50],
     [ 9.59,  5.68,  8.72,  7.88,  5.04],
     [ 3.61,  2.79,  3.36,  4.05,  5.81],
     [ 3.35,  4.52,  0.35,  5.47,  3.35],
     [ 8.69,  3.79,  9.86,  1.90,  7.80]]

和第0列,第1列,第2列,第3列和第4列分别具有值C = [3, 3, 3, 2, 3]

现在,我想根据值A对它们进行排序,即具有最高值的列是第一列,等等。我会得到:

S = sort C in decreasing order
S = [4, 2, 1, 0, 3]

但是C中存在许多联系,所以我需要在第一个最小值时打破这些联系。如果总是有关系,请将它们分解为最小值,等等。否则,任意断开关系。

在我的示例中,我应该断开列4, 2, 10之间的联系,因为它们在C中具有相同的值。 (注意。列3是最后一个,因为它具有最低值并且是唯一的。)因此,让我们看一下[0, 1, 2, 4]列中的第i个最小值。

[0, 1, 2, 4]中的第一个最小值为M1 = [3.35, 2.79, 0.35, 3.35],第二个最小值为M2 = [3.61, 3.79, 3.36, 5.04]。 (在这个例子中,我们只需要查看第二个最小值。)我们有:

  • 2M1中具有最小值,它首先出现。
  • 2列之后,列1,因为它具有第二个最小值。
  • 现在,列0和列4具有相同的第一个最小值。我们必须看到他们的第二个最小值M2。由于3.61<5.04,列0位于列4之前。

因此最终排序的列是

Final = [2, 1, 0, 4, 3]

如何在Python中实现这种排序?

2 个答案:

答案 0 :(得分:2)

按降序值和已排序列对列进行排序。这样,列将首先按其最小值进行比较,将第二个最小值进行比较,依此类推:

# transpose to list of columns
a_trans = list(zip(*A))  # Py3
a_trans =      zip(*A)   # Py2

# zip columns with indeces and values
cols_c = list(zip(range(len(C)), C, a_trans))  # Py3
cols_c =      zip(range(len(C)), C, a_trans)   # Py2

# sort by desc value and sorted column
cols_c.sort(key=lambda x: (-x[1], sorted(x[2]))) 

现在您可以构建已排序的原始矩阵:

# extract columns and transpose back to rows
A_sort = list(map(list, zip(*(c for i, val, c in cols_c))))  # Py3
A_sort =      map(list, zip(*(c for i, val, c in cols_c)))   # Py2
[[4.75, 5.44, 7.41, 6.5, 0.35],
 [8.72, 5.68, 9.59, 5.04, 7.88],
 [3.36, 2.79, 3.61, 5.81, 4.05],
 [0.35, 4.52, 3.35, 3.35, 5.47],
 [9.86, 3.79, 8.69, 7.8, 1.9]]

或只是有序的indeces:

indeces = [i for i, val, c in cols_c]
[2, 1, 0, 4, 3]

如果你不介意有一个迭代器而不是元组或某事。同样,你可以省略一些演员电话。

一些参考文献:

答案 1 :(得分:1)

您可以根据列表C中给出的权重进行排序,然后使用heapq.nsmallest打破每列中至少两个最小值的关系:

import heapq
import pprint

A = [[ 7.41,  5.44,  4.75,  0.35,  6.50],
     [ 9.59,  5.68,  8.72,  7.88,  5.04],
     [ 3.61,  2.79,  3.36,  4.05,  5.81],
     [ 3.35,  4.52,  0.35,  5.47,  3.35],
     [ 8.69,  3.79,  9.86,  1.90,  7.80]]

C = [3, 3, 3, 2, 3]

A_by_cols = zip(*A) # tranpose A so we can sort by columns
f = sorted(enumerate(A_by_cols), 
           key=lambda x: (-C[x[0]], heapq.nsmallest(2, x[1])]))

pprint.pprint(f)
# [(2, (4.75, 8.72, 3.36, 0.35, 9.86)),
#  (1, (5.44, 5.68, 2.79, 4.52, 3.79)),
#  (0, (7.41, 9.59, 3.61, 3.35, 8.69)),
#  (4, (6.5, 5.04, 5.81, 3.35, 7.8)),
#  (3, (0.35, 7.88, 4.05, 5.47, 1.9))]

然后,您可以通过剥离索引和转置来重新创建列表的最终列表:

A_final = list(zip(*(x for _, x in f)))
pprint.pprint(A_final)
[(4.75, 5.44, 7.41, 6.5, 0.35),
 (8.72, 5.68, 9.59, 5.04, 7.88),
 (3.36, 2.79, 3.61, 5.81, 4.05),
 (0.35, 4.52, 3.35, 3.35, 5.47),
 (9.86, 3.79, 8.69, 7.8, 1.9)]