2010-08-01 32 views

回答

35

我计时上述建议,这里是我的结果。

首先,功能:

def f(seq): 
    # http://stackoverflow.com/questions/3382352/equivalent-of-numpy-argsort-in-basic-python/3383106#3383106 
    #non-lambda version by Tony Veijalainen 
    return [i for (v, i) in sorted((v, i) for (i, v) in enumerate(seq))] 

def g(seq): 
    # http://stackoverflow.com/questions/3382352/equivalent-of-numpy-argsort-in-basic-python/3383106#3383106 
    #lambda version by Tony Veijalainen 
    return [x for x,y in sorted(enumerate(seq), key = lambda x: x[1])] 


def h(seq): 
    #http://stackoverflow.com/questions/3382352/equivalent-of-numpy-argsort-in-basic-python/3382369#3382369 
    #by unutbu 
    return sorted(range(len(seq)), key=seq.__getitem__) 

现在,IPython的会话:

In [16]: seq = rand(10000).tolist() 

In [17]: %timeit f(seq) 
100 loops, best of 3: 10.5 ms per loop 

In [18]: %timeit g(seq) 
100 loops, best of 3: 8.83 ms per loop 

In [19]: %timeit h(seq) 
100 loops, best of 3: 6.44 ms per loop 

FWIW

+3

有趣的 - 可能平均值比3的最佳值更重要?? – JPH 2013-02-26 11:02:57

+1

平均值受到异常值的影响。您不希望结果被其他程序运行或硬件缓存未命中所污染happenstances。 – 2017-08-03 20:47:51

51

没有内置的功能,但它很容易组装一个出了了不起的工具的Python使得可供选择:

def argsort(seq): 
    # http://stackoverflow.com/questions/3071415/efficient-method-to-calculate-the-rank-vector-of-a-list-in-python 
    return sorted(range(len(seq)), key=seq.__getitem__) 

x = [5,2,1,10] 

print(argsort(x)) 
# [2, 1, 0, 3] 

它适用于Python的array.array S也是一样的方法:

import array 
x = array.array('d', [5, 2, 1, 10]) 
print(argsort(x)) 
# [2, 1, 0, 3] 
+4

+1非常Python化! – katrielalex 2010-08-01 15:07:25

+1

而不是使用(理论上是私人的)__getitem__,你也可以使用'operator.itemgetter' /'operator.attrgetter' http://docs.python.org/library/operator.html – Ender 2010-08-01 17:58:46

+0

如果'operator.itemgetter'可以是用作'__getitem__'的嵌入式替代品,我认为我已经同意了你的Ender,但据我所知,'operator.itemgetter'也需要将其封装在'lambda'表达式中。如果可以的话,我宁愿避免额外的'lambda'。 – unutbu 2010-08-01 19:57:25

2

发现了这个问题,但需要argsort为对象的列表基于一个对象属性。

扩展unutbu的答案,这将是:

sorted(range(len(seq)), key = lambda x: seq[x].sort_property)