Seite 1 von 2

Sortieren von zwei Listen nach gleichen Sotiermechanismus ?

Verfasst: Samstag 16. Juni 2007, 18:08
von kaytec
Ich habe zwei Listen und diese sollen nach den gleichen Kriterien sortiert werden.

Code: Alles auswählen

 list1 = ['Gabi', 'Depp', 'Tux', 'PG']
list2 = [11, 12, 0, 18]
Für die liste2 ist es für mich nicht das Problem, sondern für die liste1, da die Inhalte an die Werte der list2 gebunden sind. Würde ich die liste2 nach der höchsten Punktzahl sortieren, dann sollten auch so die dazugehörigen Namen sortiert werden.

gruss und dank frank

Verfasst: Samstag 16. Juni 2007, 18:21
von EyDu
Wenn die beiden Listen logisch zusammen gehören, warum packst du sie dann nicht auch in eine entsprechende Datenstruktur?

Hier noch eine mögliche Lösung zu deinem Problem:

Code: Alles auswählen

>>> list1 = ['Gabi', 'Depp', 'Tux', 'PG']
>>> list2 = [11, 12, 0, 18]
>>> l1=[]
>>> l2=[]
>>> x = sorted(zip(list2, list1))
>>> x
[(0, 'Tux'), (11, 'Gabi'), (12, 'Depp'), (18, 'PG')]
>>> for val, name in reversed(x):
	l1.append(name)
	l2.append(val)
	
>>> l1
['PG', 'Depp', 'Gabi', 'Tux']
>>> l2
[18, 12, 11, 0]
>>> 

Verfasst: Samstag 16. Juni 2007, 18:25
von kaytec
Danke EyDu !!!

Die Sortierung war nicht so mein Problem, sondern die Bindung der beiden. Das mit zip() ist super !

danke Dir

Verfasst: Samstag 16. Juni 2007, 18:41
von schlangenbeschwörer
...Oder nur mit sorted:

Code: Alles auswählen

l = [(0, 'Tux'), (11, 'Gabi'), (12, 'Depp'), (18, 'PG')]
# nach zahlen sortieren:
print sorted(l)
# nach namen:
print sorted(l, key = lambda x: x[1])

Verfasst: Samstag 16. Juni 2007, 18:59
von kaytec
Danke schlangenbeschwörer !

Das von EyDu ist für mich verständlicher und ich möchte die listen noch weiter verarbeiten. Da ist für mich die Umsetzung nach dem Beispiel von EyDu einfacher.

gruss und dank frank

Verfasst: Samstag 16. Juni 2007, 19:30
von kaytec
Es gibt doch noch ein Problem, da bei sorted() zuerst nach den Zahlenwerten und bei gleichen Zahlenwerten nach den Buchstaben sortiert wird. :?

Da kommt dann so etwas raus

1
==============================
Depp hat 13 Punkte
Bloedel hat 13 Punkte
lina hat 13 Punkte
Bush hat 13 Punkte
==============================
2
==============================
1 Platz fuer lina mit 13 Punkten
2 Platz fuer Depp mit 13 Punkten
3 Platz fuer Bush mit 13 Punkten
4 Platz fuer Bloedel mit 13 Punkten
==============================

Die Sortierung sollte aber nach der Folge der ersten Ausgabe erfolgen. Wer gleiche Punktzahl hat aber nachfolgend ist, der ist einen Platz tiefer.

grus und dank frank

Verfasst: Samstag 16. Juni 2007, 19:42
von kaytec
Hier mal den ganzen code zum Problem !

http://www.ubuntuusers.de/paste/11817/

gruss und dank frank

Verfasst: Samstag 16. Juni 2007, 20:05
von birkenfeld
Dann würde ich doch des Beschwörers Lösung, etwas abgewandelt, vorschlagen:

Code: Alles auswählen

punkte = [11, 12, 0, 18]
namen = ['Gabi', 'Depp', 'Tux', 'PG']
reihenfolge = zip(*sorted(zip(punkte, namen), key=lambda x: x[0]))
(Durch Angabe des Keys wird nur das erste Element des (Punkte, Name)-Tupels bei der Sortierung berücksichtigt, sonst wären es beide.
Dass die Namen dann in der richtigen Reihenfolge bleiben, ist das Result davon, dass Pythons Sortieralgorithmus stabil ist.

Verfasst: Samstag 16. Juni 2007, 20:52
von kaytec
Ich danke Dir birkenfeld !

Ich habe deb code mal so abgeändert, dass er bei mir funktioniert !

einzel_wertung = zip(*sorted(zip(spiel_zuege, spieler), key=lambda x: x[0]))

==============================
Heinz hat 17 Punkte
Depp hat 13 Punkte
Merkel hat 16 Punkte
PG hat 17 Punkte
==============================
[(13, 'Depp'), (16, 'Merkel'), (17, 'Heinz'), (17, 'PG')]
==============================
1 Platz fuer PG mit 17 Punkten
2 Platz fuer Heinz mit 17 Punkten
3 Platz fuer Merkel mit 16 Punkten
4 Platz fuer Depp mit 13 Punkten
==============================

Doch so stimmt die Auswertung auch nicht :?

gruss und dank frank

Verfasst: Samstag 16. Juni 2007, 20:54
von birkenfeld
Dann dreh die Sortierung einfach um:

Code: Alles auswählen

key=lambda x: -x[0]

Verfasst: Samstag 16. Juni 2007, 21:05
von kaytec
Habe ich gemacht und es kommt das heraus !

Joe hat 0 Punkte
Gabi hat 0 Punkte
Joe hat 11 Punkte
Heinz hat 0 Punkte
==============================
[(0, 'Gabi'), (0, 'Heinz'), (0, 'Joe'), (11, 'Joe')]
==============================
1 Platz fuer Joe mit 11 Punkten
2 Platz fuer Joe mit 0 Punkten
3 Platz fuer Heinz mit 0 Punkten
4 Platz fuer Gabi mit 0 Punkten
==============================

Eigentlich müsste es so sein !

Joe hat 0 Punkte
Gabi hat 0 Punkte
Joe hat 11 Punkte
Heinz hat 0 Punkte
==============================
[(0, 'Gabi'), (0, 'Heinz'), (0, 'Joe'), (11, 'Joe')]
==============================
1 Platz fuer Joe mit 11 Punkten
2 Platz fuer Joe mit 0 Punkten
4 Platz fuer Gabi mit 0 Punkten
3 Platz fuer Heinz mit 0 Punkten
==============================

Der als letztes die 0 punkte wirft ist der Verlierer

gruss und dank frank

Verfasst: Samstag 16. Juni 2007, 21:18
von birkenfeld
Ach, dass Namen doppelt vorkommen können hast du bisher unterschlagen... ;)

Aber inzwischen solltest du doch auch etwas mit den Key-Funktionen herumspielen können...

Verfasst: Samstag 16. Juni 2007, 21:22
von kaytec
Würde ich evt. können, wenn ich Deinen code verstehen würde ! Ok - jetzt kommt : lese mal das und so !

Dann zeige mir mal was ich lesen soll und ich melde mich wieder - falls ich es verstanden habe ! - melde mich auch, falls nicht !

gruss und dank frank

Verfasst: Samstag 16. Juni 2007, 21:34
von birkenfeld
Also:

Was "zip(punkte, namen)" macht, weißt du ja schon.
sorted() sortiert dann diese Liste von (Punkte, Namen)-Paaren, und zwar mit der "Keyfunktion" lambda x: -x[0].

Das heißt, auf jedes Element der Liste von (Punkte, Namen) wird diese Funktion aufgerufen, und nach diesen Ergebnissen wird sortiert.

D.h.: sei Punkte = [2,1,3] und Namen = ['a', 'b', 'c'], dann wird nach [-2,-1,-3] sortiert.

Das restliche zip(*...) ist ein Trick, mit dem die eine Liste wieder in zwei Listen auseinanderdividiert wird.

Verfasst: Samstag 16. Juni 2007, 21:40
von kaytec
Das mit zip() habe ich so halbwegs verstanden, doch ich vertsehe nicht was die lambdafunktion macht ! Sinn bei meinen Sortierproblem würde für mich machen, wenn die keys der einen liste an die anderen gebunden wären. Verändere ich die eine liste, dann verändert sich die andere - ohne die Anbindung von Bedingungen. :oops: - hat das jemand verstanden ?

gruss und dank frank

Verfasst: Sonntag 17. Juni 2007, 07:44
von Michael Schneider
Hallo Frank!
kaytec hat geschrieben:Das mit zip() habe ich so halbwegs verstanden, doch ich vertsehe nicht was die lambdafunktion macht !
"lambda x: -x[0]" definiert eine Funktion, die als Argument x (entspricht dann einem (Punkte, Name)-Paar) erhält, von dem es das erste Element extrahiert und negiert zurückgibt. Das wird vor dem Sortieren auf alle Elemente der (Punkte, Name)-Paarliste angewendet, so dass intern eine Liste von negativen Punktwerten erzeugt wird. Negativ deshalb, weil 'sorted' standardmäßig aufwärts sortiert und somit die betragsmäßig größten Werte nach oben sortiert werden. Ich hoffe, ich habe das richtig verstanden, denn dafür gibt ja noch das Attribute 'reverse' [EDIT: Argument, sorry]:
2.1 Built-in Functions hat geschrieben:sorted( iterable[, cmp[, key[, reverse]]])
kaytec hat geschrieben:Sinn bei meinen Sortierproblem würde für mich machen, wenn die keys der einen liste an die anderen gebunden wären. Verändere ich die eine liste, dann verändert sich die andere - ohne die Anbindung von Bedingungen. :oops: - hat das jemand verstanden ?
In Python gibt es für zusammengehörige Werte den Datentyp Tupel, der die zusammengehörigen Werte zu einer Einheit zusammenfasst. Die Lösungsvorschläge beruhen darauf, dass die zusammen gehörenden Namen und Werte zu einer Liste von Paaren zusammengefasst, dann sortiert und dann wieder getrennt werden.

Grüße,
Michael

Verfasst: Sonntag 17. Juni 2007, 12:48
von Michael Schneider
Hi Frank,

wie wäre es mit diesem Vorschlag als Erweiterung des bisher Gesagten:

Code: Alles auswählen

def reverse_parallel_sort(*sequences):
    i = iter(xrange(len(sequences[0])))
    return zip(*sorted(zip(*sequences), key=lambda t: (t[0], -i.next()), reverse=True))

def parallel_sort(*sequences):
    i = iter(xrange(len(sequences[0])))
    return zip(*sorted(zip(*sequences), key=lambda t: (t[0], i.next())))

p = [17, 13, 16, 17]
n = ["Heinz", "Depp", "Merkel", "PG"]
print reverse_parallel_sort(p, n)
print parallel_sort(p, n)
>>> [(17, 17, 16, 13), ('Heinz', 'PG', 'Merkel', 'Depp')]
>>> [(13, 16, 17, 17), ('Depp', 'Merkel', 'Heinz', 'PG')]
Zur Erklärung:
i = iter(xrange(...)) erzeugt ein Objekt, das bei jedem Aufruf seiner next()-Methode einen weiteren Zähler aus dem Bereich [0..len-1] berechnet und zurückgibt.
Das Hauptkonstrukt ist größtenteils gleich, nur dass die Schlüsselfunktion ein Tupel aus (Punktzahl, Rang) zurückgibt, wobei der Rang schrittweise hochgezählt wird (bzw. runter, wenn danach rückwärts sortiert wird). Bei gleicher Punktezahl wird also der Rang in der Liste berücksichtigt. Die letztgenannten Tupel werden nur für den Sortieralgorithmus erzeugt und beeinflussen nicht die (Punktzahl, Name)-Paare. Außerdem wird die Sortierorientierung über das sorted()-Attribut reverse gesteuert.

Mit diesen Funktionen kannst Du nun beliebige Sequenzen parallel so wie die Erste sortieren - aufwärts mit parallel_sort(...) und abwärts mit reverse_parallel_sort(...). Dabei sind die Ergebnislisten immer genau so lang wie die kürzeste Eingangsliste!

Grüße,
Michael

Verfasst: Sonntag 17. Juni 2007, 13:09
von BlackJack
Wozu ist `i` gut?

Verfasst: Sonntag 17. Juni 2007, 13:28
von Michael Schneider
Hi BlackJack,

i soll den Iterator speichern, der bei jedem Aufruf durch sorted hochgezählt wird. Das Problem ist, dass ich ein Objekt benötige, das innerhalb von sorted hochgezählt wird, nicht außerhalb. Hätte auch einen eigenen Generator wie

Code: Alles auswählen

i = (x for x in range(len(sequences[0])))
schreiben können, was aber nicht viel schöner ist. Es gibt sicher noch viele andere Möglichkeiten, das ist nur die, die mir spontan einfiel. Ich bin für alles offen. :-)

Grüße,
Michael

Verfasst: Sonntag 17. Juni 2007, 13:53
von BlackJack
Was das `i` *ist* habe ich ich schon verstanden, ich wollte wissen wozu man das hier braucht!?