2016-08-08 6 views
0

Mein Ziel: Sortieren Sie eine list von Produkten (dict) zuerst nach Preis, dann nach Name. Mein Problem: Str Werte mit Zahlen in ihnen sind nicht richtig sortiert (AKA "Human Sorting" oder "Natural Sorting").Python Sorting Str Preis mit zwei Dezimalstellen

fand ich diese Funktion aus einer ähnlichen Frage: Python sorting list of dictionaries by multiple keys

def multikeysort(items, columns): 
    from operator import itemgetter 
    comparers = [((itemgetter(col[1:].strip()), -1) if col.startswith('-') else 
        (itemgetter(col.strip()), 1)) for col in columns] 
    def comparer(left, right): 
     for fn, mult in comparers: 
      result = cmp(fn(left), fn(right)) 
      if result: 
       return mult * result 
     else: 
      return 0 
    return sorted(items, cmp=comparer) 

Das Problem ist, dass meine Preise str Art, wie diese sind:

products = [ 
    {'name': 'Product 200', 'price': '3000.00'}, 
    {'name': 'Product 4', 'price': '100.10'}, 
    {'name': 'Product 15', 'price': '20.00'}, 
    {'name': 'Product 1', 'price': '5.05'}, 
    {'name': 'Product 2', 'price': '4.99'}, 
] 

So sind sie alphabetisch sortiert zu werden, wie folgt:

'100.10' 
'20.10' 
'3000.00' 
'4.99' 
'5.05' 

Simi sonders, wenn ich nach Namen sortieren, bekomme ich diese:

'Product 1' 
'Product 15' 
'Product 2' 
'Product 200' 
'Product 4' 

Die Namen in „Menschen“ Ordnung (1,2,15 statt 1,15,2) aufgeführt werden sollen. Ist es möglich, das zu beheben? Ich bin ziemlich neu bei Python, also vermisse ich vielleicht etwas Vitales. Vielen Dank.

EDIT

Mehr Info: Ich bin die Liste der Produkte in eine Django-Vorlage zu senden, die die Zahlen eingegeben werden müssen ordnungsgemäß formatiert werden. Wenn ich die Preise schwebe und sie dann entschwebe, muss ich zweimal durch die Liste der Produkte iterieren, was wie Overkill aussieht.

+1

Müssen Ihre Preise Strings sein? Am besten wäre es, sie in Floats zu konvertieren – Tyler

+0

'int' Typ entfernt die Nachkommastellen ('1.00' = '1'), und' float' löscht eine Dezimalzahl ('1.00' = '1.0') was nicht funktioniert t gut in den Warenkorb! – ThePloki

Antwort

2

Ich denke, die beste Wahl, die Preise als Schwimmer zu analysieren ist (so Sie können sortieren sie):

float("1.00") 
# output: 1.0 

geben sie dann mit zwei Dezimalstellen:

"{:.2f}".format(1.0) 
# output: "1.00" 
+0

Wenn ich es so mache, dann muss ich alle Ergebnisse durchlaufen, nachdem ich sie sortiert habe, nur um sie richtig zu formatieren. Ich werde meinen Code überprüfen und prüfen, ob ich die Iteration minimieren kann. Vielen Dank. – ThePloki

1

Versuchen Sie, sie zu typecasting schwebt in der Frage und wenn Sie 2 Dezimalstellen drucken müssen, können Sie die Ausgabe wie folgt formatieren:

float_num = float("110.10") 
print "{0:.2f}".format(float_num) # prints 110.10 
3

Ihre Sortierfunktion ist Overkill. Versuchen Sie diesen einfachen Ansatz:

from pprint import pprint 

products = [ 
    {'name': 'Product 200', 'price': '3000.00'}, 
    {'name': 'Product 4', 'price': '100.10'}, 
    {'name': 'Product 15', 'price': '20.00'}, 
    {'name': 'Product 1', 'price': '5.05'}, 
    {'name': 'Product 2', 'price': '4.99'}, 
] 

sorted_products = sorted(products, key=lambda x: (float(x['price']), x['name'])) 
pprint(sorted_products) 

Ergebnis:

[{'name': 'Product 2', 'price': '4.99'}, 
{'name': 'Product 1', 'price': '5.05'}, 
{'name': 'Product 15', 'price': '20.00'}, 
{'name': 'Product 4', 'price': '100.10'}, 
{'name': 'Product 200', 'price': '3000.00'}] 

Das Wesen meiner Lösung ist die key Funktion hat ein Tupel der Sortierbedingung zurückzukehren. Tupel vergleichen lexikographisch immer, also ist das erste Element die primäre Sortierung, das zweite die sekundäre Sortierung und so weiter.

+0

Ich mag das! Das einzige Problem ist, dass die Sortierfunktion, die ich gepostet habe, eine unbegrenzte Anzahl von Sortierspalten und Negativsortierungen erlaubt. Ist es leicht, diese zwei Dinge mit Ihrer Methode zu berücksichtigen? – ThePloki

+1

Dies behebt auch nicht das zweite Problem der Sortierung nach 'Name'. – ThePloki

+0

Ja, 'sorted()' unterstützt eine beliebige Anzahl von Spalten und negative Sortierung. –

0

Bindungen brechen sollte es jeder die Saiten Sortierung der Integer-Wert aus dem Produkt verwenden, können Sie ein Tupel zurück:

products = [ 
    {'name': 'Product 200', 'price': '2.99'}, 
    {'name': 'Product 4', 'price': '4.99'}, 
    {'name': 'Product 15', 'price': '4.99'}, 
    {'name': 'Product 1', 'price': '9.99'}, 
    {'name': 'Product 2', 'price': '4.99'}, 
] 

def key(x): 
    p, i = x["name"].rsplit(None, 1) 
    return float(x["price"]), p, int(i) 

sorted_products = sorted(products, key=key) 

Welche würden Sie geben: zu

[{'name': 'Product 200', 'price': '2.99'}, 
{'name': 'Product 2', 'price': '4.99'}, 
{'name': 'Product 4', 'price': '4.99'}, 
{'name': 'Product 15', 'price': '4.99'}, 
{'name': 'Product 1', 'price': '9.99'}] 

Im Gegensatz :

[{'name': 'Product 200', 'price': '2.99'}, 
{'name': 'Product 15', 'price': '4.99'}, 
{'name': 'Product 2', 'price': '4.99'}, 
{'name': 'Product 4', 'price': '4.99'}, 
{'name': 'Product 1', 'price': '9.99'}] 

nur float(x['price']), x['name']

01.235.164 mit