Sortieren von zwei Listen nach gleichen Sotiermechanismus ?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

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
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

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]
>>> 
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Danke EyDu !!!

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

danke Dir
schlangenbeschwörer
User
Beiträge: 419
Registriert: Sonntag 3. September 2006, 15:11
Wohnort: in den weiten von NRW
Kontaktdaten:

...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])
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

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
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

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
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Hier mal den ganzen code zum Problem !

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

gruss und dank frank
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

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.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

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
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Dann dreh die Sortierung einfach um:

Code: Alles auswählen

key=lambda x: -x[0]
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

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
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

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...
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

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
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

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.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

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
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

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
Zuletzt geändert von Michael Schneider am Sonntag 17. Juni 2007, 15:56, insgesamt 1-mal geändert.
Diese Nachricht zersört sich in 5 Sekunden selbst ...
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

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
Diese Nachricht zersört sich in 5 Sekunden selbst ...
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

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
Diese Nachricht zersört sich in 5 Sekunden selbst ...
BlackJack

Was das `i` *ist* habe ich ich schon verstanden, ich wollte wissen wozu man das hier braucht!?
Antworten