2016-04-28 3 views
0

Ich habe eine Funktion, die eine Schlüsselfunktion für sorted() zurückgibt, für die das Ziel eine Liste von Dicts ist. Ein Arbeitsbeispiel ist:Sortiere eine Liste von Wörterbüchern nach einem gemeinsamen Schlüssel und verschiebe unbekannte Werte zum Ende

def sort2key(sortKey, **kwargs): 

    def attrgetter(obj): 
     try: 
      theItem = obj[sortKey] 
     except: 
      theItem = None 
     finally: 
      return theItem 

    return attrgetter 

input = [ 
    {'id':0, 'x': 2, 'y': 2}, 
    {'id':1, 'x': 1, 'y': 0}, 
    {'id':2, 'x': 0, 'y': 1} 
] 

theSort = {'sortKey': 'x'} 

output = sorted(input, key=sort2key(**theSort)) 

print(input) 
print(output) 

>>> [{'x': 2, 'id': 0, 'y': 2}, {'x': 1, 'id': 1, 'y': 0}, {'x': 0, 'id': 2, 'y': 1}] 
>>> [{'x': 0, 'id': 2, 'y': 1}, {'x': 1, 'id': 1, 'y': 0}, {'x': 2, 'id': 0, 'y': 2}] 

Allerdings möchte ich die Funktion fehlende Werte zu handhaben zu können:

[ 
    {'id':0, 'x': 2, 'y': 2}, 
    {'id':1, 'x': 1, 'y': 0}, 
    {'id':2,   'y': 1} 
] 

Aber der vorherigen Code den dict mit dem fehlenden x zu Beginn zwingen würde, - es muss abhängig von der Sortiereinstellung entweder Start oder Ende sein:

Darüber hinaus der Wert von x in diesem Fall sind Zahlen, aber sie könnten Strings oder andere Arten sein.


Gibt es eine Möglichkeit, unbekannte Werte zu Ende zu zwingen?

Antwort

0

Sie können eine Lambda-Funktion und die get-Methode vom Typ dict verwenden. Hier ist der Code:

Input = [ 
     {'id':0, 'x': 2, 'y': 2}, 
     {'id':1, 'x': 1, 'y': 0}, 
     {'id':2, 'x': 0, 'y': 1} ] 

    sortKey = 'id' # Use max for ToEnd setting 
    unknown = max([ elt[sortKey] for elt in Input if sortKey in elt ]) 

    Output = sorted(Input, key=lambda X: X.get(sortKey, unknown)) 

    for elt in Output: 
    print(elt) 

dict.get (a, b) gibt den Wert an Taste a verbunden, wenn sie oder die b Standardwert vorhanden ist.

Für gemischte Daten können Sie verwenden: so wird es möglich sein, verschiedene Arten Werte zu vergleichen.

Sie können zwischen den ToEnd- und ToStart-Einstellungen nur mit den Funktionen min/max wechseln.

+1

In Python 3.4 Sie auf die dict.get Bezug würde (a, b) Verfahren. Ihre Antwort bringt jedoch einen guten Punkt. Ich habe nicht unbedingt Nummern, also funktioniert 'inf' nicht. Der Wert könnte eine Zeichenfolge sein - ich werde die Frage aktualisieren. – timyha

+0

Sie haben Recht. Wir haben die Wahl zwischen "get" und "setdefault", die frühere Methode liefert den Wert, aber ändert nicht das 'dict' als' setdefault'. Für die Einstellungen "ToEnd" und "ToStart" können Sie eine Min \ Max-Funktion hinzufügen, so dass das fehlende Element immer direkt zur Start-/Endposition gehört. Ich werde die Antwort bearbeiten. –

+0

Danke nino, mit min()/max() für verschiedene Typen ist eine gute Idee. – timyha

0

Hier ist ein funktionierendes Beispiel mit @ nino_701 der comment

def sort2key(sortKey, minVal, maxVal, unknowns='toEnd', **kwargs): 

    def attrgetter(obj): 
     try: 
      theItem = obj[sortKey] 
     except: 
      theItem = minVal if unknowns == 'toStart' else maxVal 
     finally: 
      return theItem 

    return attrgetter 

input = [ 
    {'id':0, 'x': 2, 'y': 2}, 
    {'id':1,   'y': 0}, 
    {'id':2, 'x': 0, 'y': 1} 
] 

theSort = {'sortKey': 'x'} 

minVal = min((x[theSort['sortKey']] for x in input if theSort['sortKey'] in x)) 
maxVal = max((x[theSort['sortKey']] for x in input if theSort['sortKey'] in x)) 

output = sorted(input, key=sort2key(minVal = minVal, maxVal = maxVal, unknowns='toStart', **theSort)) 
output2 = sorted(input, key=sort2key(minVal = minVal, maxVal = maxVal, unknowns='toEnd', **theSort)) 

print(input) 
print(output) 
print(output2) 

>>> [{'id': 0, 'y': 2, 'x': 2}, {'id': 1, 'y': 0}, {'id': 2, 'y': 1, 'x': 0}] 
>>> [{'id': 1, 'y': 0}, {'id': 2, 'y': 1, 'x': 0}, {'id': 0, 'y': 2, 'x': 2}] 
>>> [{'id': 2, 'y': 1, 'x': 0}, {'id': 0, 'y': 2, 'x': 2}, {'id': 1, 'y': 0}] 
+0

Das einzige Problem dabei ist, dass ich die MinVal und MaxVal jedes Mal manuell bereitstellen muss - ich würde es vorziehen, dies nicht tun zu müssen. – timyha

Verwandte Themen