2016-06-24 11 views
0

Ich habe eine Liste von Objekten in Python 3.5.1 mit mehreren benannten Attributen. Die Liste stellt eine Gruppe von C-Variablen dar, und daher hat jedes Objekt drei benannte Attribute, die drei gemeinsamen Basistypen entsprechen: uint8, uint16 und uint32.Python3 Objekte nach mehreren benannten Attributen sortieren

class variableList(object): 
    def __init__(self, eight, sixteen, thirtytwo): 
     self.size_8 = eight 
     self.size_16 = sixteen 
     self.size_32 = thirtytwo 

Der Wert dieser benannte Attribute entweder (Nonetype) None oder (str)'E'. Pro Objekt hat nur eines der genannten Attribute einen Nicht-Nicht-Wert.

Ich möchte diese Liste von Objekten so sortieren, dass alle Objekte mit non-None-Wert für size_32 oben sind, gefolgt von size_16, gefolgt von size_8.

In Python 2.7.1 habe ich erfolgreich das, aber es fühlte sich wie schwarze Magie:

size_filtered_list = sorted(filtered_list, key=lambda y: (y.size_32, y.size_16, y.size_8)) 

aber in 3.5.1 dies nicht mehr funktioniert. Vorschläge?

+0

Wenn Sie '__lt__' und' __eq__' Methoden definieren, können Sie Ihre Variablen ohne 'Schlüssel' Argument sortieren. Weil ich mit C nicht vertraut bin, könntest du im Grunde erklären, was '(str) 'E'' in Python bedeuten würde? –

+0

Gibt es einen Grund, warum Sie effektiv boolesche Flags als 'None' und' 'E'' verwenden und nicht nur 'False' und' True' verwenden? Wenn Sie keine inkompatiblen Typen verwenden, könnte Ihre Sortierung zu einem Import am Anfang der Datei "from operator import attrgetter" mit der Sortierung vereinfachen: 'sorted (filtered_list, key = attrtretter ('size_32', 'size_16') , 'size_8')) ', was in allen Python-Versionen gut funktioniert, weil Sie vergleichbare Typen sortieren. – ShadowRanger

+0

Oder wenn Sie eine weitere Variable wie in 'self.size_8_exist' hinzufügen, können Sie immer noch dieselbe Technik verwenden. – arewm

Antwort

0

Ich würde nur die Vergleichsoperatoren für die Klasse implementieren. Angenommen, Sie möchten nicht basierend auf den in den einzelnen Attributen gespeicherten Werten sortieren, sollte diese Implementierung funktionieren.

class variableList(object): 
    def __init__(self, eight, sixteen, thirtytwo): 
     self.size_8 = eight 
     self.size_16 = sixteen 
     self.size_32 = thirtytwo 

    def __lt__(self, other): 
     if self.size_8 is not None: 
      return self != other 
     elif self.size_16 is not None: 
      return True if other.size_32 is not None else False 
     else: 
      return False 

    def __eq__(self, other): 
     if self.size_8 is not None: 
      return other.size_8 is not None 
     elif self.size_16 is not None: 
      return other.size_16 is not None 
     else: 
      return other.size_32 is not None 

Und der Vollständigkeit halber können Sie auch die größer ist als Operator implementieren, aber es ist nicht notwendig, für die Sortierung:

def __gt__(self, other): 
     if self.size_32 is not None: 
      return self != other 
     elif self.size_16 is not None: 
      return False if other.size_32 is not None else True 
     else: 
      return False 

Wenn Sie die Werte der gleichen Typen sortiert werden sollen, werden Sie müssen eine weitere Verschachtelungsebene hinzufügen, um diese Werte zu vergleichen.

+0

verlassen Sie sich nie auf die Implementierungsdetails, dass die Python-Sortierung nur '__lt__' verwendet, Sie können' functools.total_ordering' verwenden, um die anderen Vergleichsmethoden zu automatisieren, sobald '__eq__' und einer davon definiert ist. –

+0

Danke, das wusste ich nicht. Ich bin immer paranoid, dass ich mit den Vergleichsoperatoren einen dummen Fehler gemacht habe, also wäre es besser, die anderen zu automatisieren, als sie alle selbst zu schreiben. – arewm

+0

Sie sind richtig, in diesem Fall scheint das viel weniger fehlerhaft, aber immer noch y = variableList (1, None, None); Drucken (y

1

Sie sollten zu kompatiblen Typen wechseln; Sortieren None und 'E' ist unsinnig, und während Python 2 "arbiträre aber konsistente" Sortierregeln für inkompatible Typen es erlaubt, ist es schrecklich Praxis. Wenn die einzigen Werte None und 'E' sind, dann sind sie wirklich nur schreckliche Versionen von booleans; Sie könnten genauso einfach False und True verwenden und Ihre key Funktion würde sowohl in Py2 und Py3 funktionieren; Sie kann mit der „Optimierung“ ein wenig auch mit operator.attrgetter:

from operator import attrgetter 

size_filtered_list = sorted(filtered_list, key=attrgetter('size_32', 'size_16', 'size_8')) 

Alternativ den ursprünglichen lambda basierten Code verwenden, können Sie es durch das Ersetzen None mit dem leeren String im key, so dass Sie kompatible Typen vergleichen funktioniert (während nach wie vor die Behandlung der None als weniger als jede andere Zeichenfolge):

size_filtered_list = sorted(filtered_list, key=lambda y: (y.size_32 or '', y.size_16 or '', y.size_8 or '')) 

Es ist irgendwie albern, aber so wird mit None und 'E' für das, was zu boolean Datenmengen.

Verwandte Themen