2012-09-27 9 views
7

Często używam klas namedtuple. Zastanawiam się dzisiaj, czy istnieje dobry sposób wdrożenia niestandardowego sortowania dla takiej klasy, tj. Uczynienie domyślnego klucza sortowania nie pierwszym elementem (potem drugim, trzecim itd.) O nazwietakle.Niestandardowe sortowanie w klasie o nazwie zwanej pon.

Moim pierwszym odruchem było wdrożenie __lt__ i __eq__ i niech total_ordering zrobić resztę (to wypełnia le, ne, gt, GE):

from collections import namedtuple 
from functools import total_ordering 


@total_ordering 
class B(namedtuple('B', 'x y')): 
    def __lt__(self, other): 
     return self.y < other.y 

Jednakże:

def test_sortingB(): 
    b1 = B(1, 2) 
    b2 = B(2, 1) 
    assert b2 < b1 # passes 
    assert b2 <= b1 # fails 

oh, prawo ... total_ordering wypełnia tylko inne metody if they are missing. Ponieważ tuple/namedtuple ma takie metody, total_ordering nic nie robi dla mnie.

Więc myślę, że moje możliwości są

  1. zaprzestać używania namedtuple i po prostu stworzyć własną nudne lekcje, nadal używać total_ordering
  2. nadal korzystać namedtuple i wdrożyć wszystkie 6 metod porównywania
  3. nadal korzystać namedtuple i włóż wartość sortowania jako pierwsze pole. Na szczęście nie mam zbyt wielu instancji klasy, ale zazwyczaj polegam tylko na kolejności pól, aby je zainicjować, co może być nieprzyjemne. Może to zły nawyk.

Sugestie dotyczące najlepszego sposobu rozwiązania tego problemu?

+0

Dlaczego po prostu nie utworzysz nazwy z polami w kolejności, według której chcesz sortować? – BrenBarn

+0

Nie zdawałem sobie sprawy, że chciałbym posortować/zmaksymalizować itd., Dopóki nie utworzyłem go i użyłem go przez jakiś czas. Mogę więc dodać pole wiodące jako pole sortowania, ale może to być trochę uciążliwe. – pfctdayelise

+1

Ale w jaki sposób używasz namedtuple?Dobrą rzeczą w przypadku namedtuple jest to, że umożliwia dostęp do elementów po nazwie, dzięki czemu możesz zmienić swoją nazwanątę, aby pola były we właściwej kolejności i nie wpłynęły na twój kod, o ile będziesz mieć dostęp do pól po nazwie (która prawdopodobnie robi, czy też dlaczego używał namedtuple?). – BrenBarn

Odpowiedz

10

OPCJA 1. Użyj mixin i zastosować total_ordering tej

@total_ordering 
class B_ordering(object): 
    __slots__ =()     # see Raymond's comment 
    def __lt__(self, other): 
     return self.y < other.y 

class B(B_ordering, namedtuple('B', 'x y')): 
    pass 

OPCJA 2. Stwórz własny dekorator na podstawie total_ordering i po prostu użyj go zamiast:

+1

+1, rozwiązanie mixin jest miłe. – nneonneo

+0

Czy istnieje znacząca różnica w obciążeniu dla opcji 1 w porównaniu z opcją 2? – Will

+0

+1. Opcja 1 to bezpośrednie rozwiązanie problemu total_ordering, polegającego na uzupełnianiu brakujących wartości. @ Czy obciążenie dla Opcji 1 jest bliskie zeru (jeden dodatkowy krok w kolejności rozwiązywania metody @JohnLaRooy, sugeruję dodanie \ _ \ _ slotów \ _ \ _ =() do Opcji 1, aby przywrócić efektywność pamięci –

1

Moja rada polega na utworzeniu Twojej nazwanej skrzynki z polami w drugiej, w której chcesz je posortować. Być może będziesz musiał zmienić części kodu, w których tworzysz swoje wartości (np. Zmienić someTuple("name", 24) na someTuple(24, "name"), ale generalnie wartości są tworzone w mniejszej liczbie miejsc, niż są używane, więc nie powinno to być zbyt dużą transakcją. unika się kłopotów z pisania wszystkie metody porównania, a jako bonus unika również dodatkowy narzut wydajności posiadania tych niestandardowych metod porównawczych zwane przez cały czas.

3

Jeżeli, jak sugeruje Twoje pytanie, zainteresowanie jest tylko w sortowania namedtuples przez klucz alternatywny, dlaczego nie wykorzystać ten rodzaj/klasyfikowane key argument z funkcji attrgetter:

>>> from collections import namedtuple 
>>> from operator import attrgetter 
>>> P = namedtuple("P", "x y") 
>>> p1 = P(1, 2) 
>>> p2 = P(2, 1) 
>>> sorted([p1, p2], key=attrgetter("y")) 
[P(x=2, y=1), P(x=1, y=2)] 

można przejść nawet dalej i zdefiniuj własną funkcję sortowania:

>>> from functools import partial 
>>> sortony = partial(sorted, key=attrgetter("y")) 
>>> sortony([p1, p2]) 
[P(x=2, y=1), P(x=1, y=2)] 
+0

jeszcze nie istnieje, więc albo trzeba go dodać, albo użyć metody cmp, która wygląda na 2 pola i zawiera trochę logiki (mój przykładowy kod jest zbyt uproszczony) – pfctdayelise

Powiązane problemy