Seite 1 von 1

Listen nach mehreren Vorgaben sortieren

Verfasst: Freitag 10. Februar 2006, 15:57
von Bennhardt
Hallo,

ich hatte schon in diversen Cookbooks geschaut und auch hier gesucht.
Ich muss Listen in einer Liste nach 2 Suchkriterien sortieren.
Das sieht etwas so aus:

[["Bob","34 Jahre","183 cm","45 kg"],["Bob","67 Jahre","209 cm","120 kg"],["Charly","23 Jahre","172","56 kg"]] usw.

Das Problem: Nach dem ersten Index soll immer sortiert werden (also "Bob","Bob","Charly" etc.), jedoch soll per Variable mitgegeben werden, nach welchem Index ich als nächstes sortiere also nach Alter, Größe, Gewicht.
Man soll am Ende eine Liste bekommen, in der alle Leute nach Namen sortiert sind, aber eben variabel (wie ich das löse ist schon klar) nach Gewicht ODER Größe ODER Alter.

Ich hab das schon versucht:


Code: Alles auswählen

a = [["Bob","34 Jahre","183 cm","45 kg"],["Bob","67 Jahre","209 cm","120 kg"],["Charly","23 Jahre","172","56 kg"]]
def compare(a,b):
    return cmp(a[1],b[1])
a.sort(compare)

print a
Hier kann ich wenigstens schon mal aussuchen, nach welchem Index ich sortieren möchte. Das nütz mir aber nix, weil ich eben nur nach EINEM index sortieren kann.
Ich hatte mir schon überlegt, für jeden Namen eine eigene Liste zu erstellen, aber das ist nicht variabel genug.
Wie kann man da rangehen?

Verfasst: Freitag 10. Februar 2006, 16:34
von helmut
Hallo,

ich befuerchte meine Loesung ist nicht sehr "pythonisch"; es scheint aber zu klappen.

Code: Alles auswählen

a = [["Bob","94 Jahre","183 cm","45 kg"],["Bob","67 Jahre","209 cm","120 kg"],["Charly","23 Jahre","172","56 kg"]]
inx2=1
def compare(a,b):
    if a[0]<b[0]:
        return -1
    elif a[0]==b[0]:
        return cmp(a[inx2],b[inx2])
    else:
        return 1
    
a.sort(compare)
print a 
#[['Bob', '67 Jahre', '209 cm', '120 kg'], ['Bob', '94 Jahre', '183 cm', '45 kg'], ['Charly', '23 Jahre', '172', '56 kg']]
Helmut

Verfasst: Freitag 10. Februar 2006, 17:12
von mawe
Hi!

Ich vereinfache das mal, und nehme Alter, Grösse, ... als Zahlen.

Code: Alles auswählen

 l = [["Bob", 34, 183, 45],["Sepp", 67, 209, 120], ["Alice", 23, 172, 56],["Bob", 77, 20, 11]]
n = [((x[0],x[1]),x) for x in l]
n.sort()
print [i[1] for i in n]
Ich erstelle also eine List n. Diese hat als Element immer ein Tupel mit den Grössen nach denen sortiert werden soll (also hier Name und Alter) und den ursprünglichen Listeneintrag selbst. n wird dann sortiert, vorrangig nach den Elementen in den Tupel. Dann printe ich die zweiten Elemente der sortierten Liste, und das sind ja die ursprünglichen Einträge.
Ich hoffe ich hab richtig gedacht ;)

Gruß, mawe

Verfasst: Freitag 10. Februar 2006, 19:01
von Bennhardt
Klasse! Teste ich, sobald ich wieder im Büro bin! Jetzt hab ich erstmal FREIZEIT :D

Danke schonmal im Voraus!!

Schönes WE wünscht,
Ben

Verfasst: Samstag 11. Februar 2006, 00:25
von BlackJack
Helmuts Lösung etwas pythonischer:

Code: Alles auswählen

persons = [["Bob","94 Jahre","183 cm","45 kg"],
           ["Bob","67 Jahre","209 cm","120 kg"],
           ["Charly","23 Jahre","172","56 kg"]]

def make_compare(second_index):
    def compare(a, b):
        return cmp(a[0], b[0]) or cmp(a[second_index], b[second_index])
    return compare

persons.sort(make_compare(1))
print persons

Verfasst: Sonntag 12. Februar 2006, 02:01
von woolfy
Hier noch eine aufgebohrte Variante, die gerade in meinem Zustand geistiger Umnachtung entstanden ist.

Damit kann man Daten nach x-beliebig vielen Kriterien sortieren und das jeweils auf- bzw. absteigend.
Das könnte man nun noch mit getattr() auf eine Liste von Objekten abändern, um nach deren Eigenschaften sortieren zu können.

Performance hab ich mir noch nicht angesehen und das mit dem eval kanns noch nicht sein. Vielleicht hat jemand noch ein paar Ideen...

Code: Alles auswählen

data = [
    [1,'a','x'],
    [1,'a','y'],
    [1,'a','z'],
    [1,'b','x'],
    [1,'b','y'],
    [1,'b','z'],
    [1,'c','x'],
    [1,'c','y'],
    [1,'c','z'],
    [2,'a','x'],
    [2,'a','y'],
    [2,'a','z'],
    [2,'b','x'],
    [2,'b','y'],
    [2,'b','z'],
    [2,'c','x'],
    [2,'c','y'],
    [2,'c','z'],
    [3,'a','x'],
    [3,'a','y'],
    [3,'a','z'],
    [3,'b','x'],
    [3,'b','y'],
    [3,'b','z'],
    [3,'c','x'],
    [3,'c','y'],
    [3,'c','z'],
]

def comp(sort_criteria):
    def helper(a,b):
        return eval(" or ".join([(order=='asc' and str(cmp(a[criteria],b[criteria])) or str(cmp(b[criteria],a[criteria]))) for criteria, order in sort_criteria]))
    return helper

criteria = ((1,'asc'),(2,'desc'),(0,'asc'))
data.sort(comp(criteria))
for x in data:
    print x
LG
Jens

Verfasst: Montag 13. Februar 2006, 09:02
von Bennhardt
Ja super! Genau das, was ich brauche!
Performance ist nicht so ausschlaggebend, da die Liste, die ich zu sortieren habe nicht allzu groß ist.