2012-08-28 9 views
6

Ho una serie di vettori e voglio ordinarli per lunghezza:__key__ parametro per le classi in Python

class Vector: 

    def __init__(self, x, y): 
     self.x, self.y = x, y 

    def __add__(a, b): 
     return Vector(a.x + b.x, a.y + b.y) 

    def __str__(a): 
     return str(a.x) + ' ' + str(a.y) + '\n' 

    def __key__(self): 
     return self.x * self.x + self.y * self.y 


a = [] 
a.append(Vector(1,2)) 
a.append(Vector(1, 1)) 
a.sort() 
print("".join(map(str,a))) 

si dice: "tipi non ordinabile: Vector() < Vector()" Mi vuole creare i metodi lt, gt ... Ma voglio ordinare senza usare cmp. È possibile?

+3

si noti che probabilmente non dovrebbe usare '__key__' come il nome di uno dei tuoi metodi. i nomi dei metodi messi tra parentesi da coppie di caratteri di sottolineatura sono riservati per mezzo speciale dalla specifica (questo significa che in qualsiasi momento Guido potrebbe decidere di aggiungere '__key__' come parte del modello di dati python e il tuo metodo potrebbe risultare piuttosto interessante (indesiderato).) – mgilson

+0

Inoltre, se stai solo cercando una buona classe vettoriale, potresti voler dare un'occhiata a 'numpy'. Fornisce "ndarray" che si comportano in modo molto simile ai vettori, supportano una forma di indicizzazione molto interessante (e utile) e fanno tutte le operazioni matematiche in C che li rende un po 'più veloci di quelli che otterresti con il rollover implementazione. – mgilson

+1

@mgilson sembra che OP si aspettasse che '__key__' sia già definito come parte del modello di dati Python, con un comportamento analogo al parametro chiave' key' su 'list.sort'. –

risposta

2

Python docs says che lt/le/GT/ge/eq/ne sono

[...] i metodi cosiddetti “ricchi” di confronto, e sono chiamati per operatori di confronto a preferenza di __cmp__()

Se si implementa un metodo __cmp__(self, other), dovrebbe essere utilizzato per operazioni di confronto/ordinamento.

+3

Vale la pena ricordare che '__cmp__' non è più usato in python 3.x – mgilson

+0

@mgilson, e dato l'uso' stampa', OP potrebbe già usare Py3. – lvc

+0

@Ivc - Sì, e sintassi "vecchio stile" per la dichiarazione di classe (anche se ciò potrebbe essere dovuto al fatto che l'OP non sa di ereditare sempre da 'object' in python 2.x). – mgilson

6

Implementare __lt__ e __eq__ e quindi utilizzare il decoratore di classe functools.total_ordering per ottenere il resto dei metodi di confronto.

Se non ha senso avere i vettori ordinato così, allora si può sempre e solo utilizzare la parola chiave key-sort (o sorted per questo):

mylist.sort(key = lambda v: v.x**2 + v.y**2) 
+0

Questo è pulito, ma semanticamente un po 'incerto: i vettori non sono realmente ordinati in base alla lunghezza, poiché ad esempio (0,1) e (1,0) sono diversi ma paragonabili. – katrielalex

+0

@katrielalex - Un po 'vero. Sei libero di implementare '__eq__' e' __lt__' come meglio credi.Si potrebbe rendere '__eq__' definito come' self.x == other.x e self.y == other.y' per esempio. In questo caso particolare, non vedo davvero come un vettore possa essere "meno di un altro", quindi in questo caso, probabilmente userò di default un "tasto" per l'ordinamento, ma ho pensato che avrei incluso 'functools .total_ordering' poiché assomiglia più a quello che sembra OP sta cercando di fare. (È anche un decoratore utile da sapere a prescindere). – mgilson

+0

Penso che questa sia una bella idea, e penso che dovrebbe funzionare in base al ['source'] (http://hg.python.org/cpython/file/2.7/Lib/functools.py#l53). La domanda è: 'total_ordering' definisce' __gt__' in un modo che restituisce 'False' quando' x' e 'y' sono uguali? E sembra dalla fonte. In questo caso il risultato non sarà un ordine totale, ma un [preordine totale] (http://en.wikipedia.org/wiki/Strict_weak_ordering#Total_preorders); ciò che è totale qui è davvero il _relation_, piuttosto che l'ordine. – senderle

6

Hai due varianti qui : implementare __cmp__ funzione nel Vector classe o effettuare una cernita in questo modo:

... 
a.sort(key=Vector.__key__) 
+1

Suggerirei di rinominare il metodo '__key__' in' __len__', poiché il valore restituito è in realtà la lunghezza del vettore. Quindi usa 'a.sort (key = len)', che mostra l'intento molto più chiaramente. –

+4

@lazyr certamente no! '__len__' è per la lunghezza * delle sequenze *; Python si aspetta che restituisca un intero. (Inoltre, il valore attualmente restituito è il quadrato della lunghezza.) –

+2

@lazyr - Sono d'accordo con il principio che "__key__" non è il nome migliore (anche se a parte forse significa qualcosa di specifico in futuro, non è 'molto specifico), ma '__len__' è un po' discutibile, dal momento che' help (len) 'dice che è" il numero di elementi di una sequenza o di una mappatura ". Probabilmente lo definirei come una funzione separata (non un metodo) chiamata qualcosa come 'norma'. – lvc

Problemi correlati