2010-08-01 8 views

Répondre

35

J'ai chronométré les suggestions ci-dessus et voici mes résultats.

Tout d'abord, les fonctions:

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__) 

Maintenant, la session 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

Intéressant - probablement la moyenne est plus importante que le «meilleur» de 3 (?) – JPH

+1

La moyenne est affectée par les valeurs aberrantes Vous ne voulez pas que les résultats soient pollués par d'autres programmes en cours d'exécution les événements. –

51

Il n'y a aucune fonction intégrée, mais il est facile d'assembler un sur des outils formidables Python met à la disposition:

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] 

Il fonctionne sur Python array.array de la même façon:

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

+1 Très Pythonic! – katrielalex

+1

Au lieu d'utiliser le __getitem__ (théoriquement privé), vous pouvez également utiliser 'operator.itemgetter' /' operator.attrgetter' http://docs.python.org/library/operator.html – Ender

+0

Si 'operator.itemgetter' peut être Utilisé comme remplacement de '__getitem__', je pense que j'étais d'accord avec toi Ender, mais pour autant que je puisse voir,' operator.itemgetter' nécessiterait aussi de l'entourer d'une expression 'lambda'. Je préférerais éviter le «lambda» supplémentaire si je le pouvais. – unutbu

2

Trouvé cette question, mais nécessaire argsort pour une liste des objets en fonction de une propriété d'objet.

L'extension de la réponse de unutbu, ce serait:

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