对未排序列表进行索引并对列表进行排序

8

以下是我需要在我的列表中执行的逻辑步骤

a = [[5,2],[7,4],[0,3]]
  1. sort the list of lists in such a way that the output looks something like

    7,5,4,3,2,0
    
  2. take the coordinates of the sorted elements in the original list, which in this case should produce as output

    (1,0)
    (0,0)
    (1,1)
    (2,1)
    (0,1)
    (2,0)
    

我尝试使用sort、sortedargwhere,但是以不同的方式使用后,得到的结果并不合理。我猜这是因为sortsorted只能按照一个轴排序列表。


你只想输出索引,还是也想输出值(即7、5、4、3、2、0)? - PM 2Ring
@PM2Ring 我不需要输出这些值,但我需要能够获取它们以进行进一步的计算。 - johnhenry
1
重复的情况怎么办? - Jodrell
5个回答

8
创建一个字典,其中键是实际坐标,值为数字本身,例如:
>>> a = [[5, 2], [7, 4], [0, 3]]
>>> positions = {
...     (idx1, idx2): col
...     for idx1, row in enumerate(a)
...     for idx2, col in enumerate(row)
... }
>>> positions
{(0, 1): 2, (2, 0): 0, (0, 0): 5, (1, 0): 7, (1, 1): 4, (2, 1): 3}

现在,根据它们的值对positions的键(坐标)进行排序,就像这样:

>>> sorted(positions, key=positions.get, reverse=True)
[(1, 0), (0, 0), (1, 1), (2, 1), (0, 1), (2, 0)]

8
这段代码适用于列表的列表。内部列表的长度可以不同。
在每个级别上,我们使用enumerate迭代列表以获取列表项及其索引。在顶层,每个项目都是另一个列表,内部循环遍历每个列表以获取它们的索引和值,并将索引(作为元组)存储在包含该值的元组中。然后,我们对元组列表(b)按值进行排序,然后使用zip将其拆分为所有索引的元组和所有值的元组。
from operator import itemgetter

a = [[5, 2], [7, 4], [0, 3]]

b = [((i, j), v) for i, t in enumerate(a) for j, v in enumerate(t)]
b.sort(key=itemgetter(-1), reverse=True)
print(b)
coords, vals = zip(*b)
print(vals)
print(coords)

输出

[((1, 0), 7), ((0, 0), 5), ((1, 1), 4), ((2, 1), 3), ((0, 1), 2), ((2, 0), 0)]
(7, 5, 4, 3, 2, 0)
((1, 0), (0, 0), (1, 1), (2, 1), (0, 1), (2, 0))

2
也被称为施瓦茨变换 - Bergi
@Bergi 很好地发现了。 :) 在 Python 中很少需要显式使用它(尽管我猜在 sort / sorted 中使用键函数的任何用途在底层都是 Schwartzian 排序),所以能够在这里有一个很好的借口来使用它,感觉还是挺有趣的。 - PM 2Ring

2
你可以使用一系列列表推导和 zip 块,虽然可读性会受到影响:
n, idxs = zip(*sorted(zip([i for sl in a for i in sl], [(col, row) for col in range(len(a)) for row in range(len(a[col]))]), key=lambda x: x[0], reverse=True))

print n, idxs
>>> (7, 5, 4, 3, 2, 0) ((1, 0), (0, 0), (1, 1), (2, 1), (0, 1), (2, 0))

如果你需要一个字典,只需将zip(*..)层替换为dict()

2

使用 Numpy,当你处理较大的数组时,它比普通的Python代码快得多:

In [21]: a = np.array([[5,2],[7,4],[0,3]])
In [22]: x, y = np.unravel_index((-a).argsort(axis=None), a.shape)

In [23]: indices = np.column_stack((x, y))

In [24]: indices
Out[24]: 
array([[1, 0],
       [0, 0],
       [1, 1],
       [2, 1],
       [0, 1],
       [2, 0]])

In [25]: a[x, y]
Out[25]: array([7, 5, 4, 3, 2, 0])

对于其他的索引,如果我需要使用前两个索引[1,0]和[0,0](例如),最好的使用方法是什么?我的意思是:考虑到我需要提取a [1] [0]和a [0,0],我该怎么做? - johnhenry
@johnhenry 请查看更新。这是一种更通用的方法,可以通过简单的索引来获取排序后的数组。 - Mazdak

1
你可以将列表展平,然后使用它进行排序和查找索引。
a = [[5,2],[7,4],[0,3]]
c = reduce(lambda x, y: x+y, a)
b = sorted(c, reverse=True)
for i in b:
    print c.index(i)/2, c.index(i)%2

输出:

1 0 
0 0
1 1
2 1
0 1
2 0

1
如果有任何重复的值,这种方法可能不太有效。此外,它假定内部列表始终恰好有2个项目。 - PM 2Ring
@PM2Ring,除非OP澄清,我认为假设内部列表恰好有两个项目是合理的。 - vks
1
好的,但是关于重复值的观点仍然成立。 ;) - PM 2Ring
@PM2Ring,是的,再次提醒OP需要澄清他是否总是想要第一位置,还是在重复情况下要实际位置!!!不过这很容易解决 :) - vks

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接