Sortierung von Listen (Tupel-Listen) anhand einer Liste

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.
Antworten
rads
User
Beiträge: 153
Registriert: Freitag 26. März 2010, 15:51

Hallo,

da es sich wohl um ein leichteres Problem handelt, mach ich es kurz.

Code: Alles auswählen

dicFull = {'field4':10,'field2':20,'field1':30,'field3':40}
    partList = ['field4','field3']
Ich möchte partList anhand der value-Werte aus dem Dict dicFull sortieren.

Wie mache ich das in einer eleganten Version?

Schonmal vielen Dank

Grüße Stefan
Zuletzt geändert von rads am Mittwoch 14. Juli 2010, 08:21, insgesamt 1-mal geändert.
BlackJack

Code: Alles auswählen

part_list.sort(key=dic_full.__getitem__)
rads
User
Beiträge: 153
Registriert: Freitag 26. März 2010, 15:51

Super vielen Dank BlackJack.
rads
User
Beiträge: 153
Registriert: Freitag 26. März 2010, 15:51

Noch eine Frage,

angenommen in part_list gibt es Einträge die in dic_full nicht auftreten, dann würde er momentan eine Key-Not Found exception werfen.
Ist es möglich diese Werte "zu ignorieren" wobei ich meine das sich "einfach" am Ende unsortiert verbleiben?

Oder würde das nur über den Weg gehen, nicht im dict vorhandene Werte aus der liste entfernen und nachträglich wieder hinzufügen?

Grüße

Beispiel:

Code: Alles auswählen

dicFull = {'field4':40,'field2':20,'field1':30,'field3':10}
    partList = ['field2','field4','field3','field5']
    partList.sort(key=dicFull.__getitem__)
    print partList

Traceback (most recent call last):
  File "....py", line 13, in <module>
    partList.sort(key=dicFull.__getitem__)
KeyError: 'field5'
Trichter
User
Beiträge: 45
Registriert: Montag 20. April 2009, 10:21

Das könnte man vielleicht mit einem defaultdict machen, das standardmäßig einen sehr großen Wert liefert, wenn der Eintrag nicht vorhanden ist.
rads
User
Beiträge: 153
Registriert: Freitag 26. März 2010, 15:51

Im moment mache ich es halt wie folgt (Testimplementierung)

Code: Alles auswählen

 dicFull = {'field4':40,'field2':20,'field1':30,'field3':10}
    partList = ['field2','field4','field3','field5']
    tmpList = []
    for part in partList:
        if not dicFull.has_key(part):
            partList.remove(part)
            tmpList.append(part)
    partList.sort(key=dicFull.__getitem__)
    partList = partList + tmpList
    print partList
Sicherlich nicht die idealiste Liste, aber so wie ich den sort - Befehl verstehe gibts ja keine Möglichkeit für einen skipl.
Zuletzt geändert von rads am Dienstag 13. Juli 2010, 13:59, insgesamt 1-mal geändert.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Manchmal hilft es auch ungemein nicht einfach nur Code blind zu übernehmen, sondern auch in die Dokumentation zu schauen was sort noch für mögliche Argumente hat.
Das Leben ist wie ein Tennisball.
BlackJack

@rads: Du könntest auch einfach eine Funktion schreiben die dafür sorgt, dass für Elemente die nicht in dem Dictionary vorkommen, grundsätzlich ein höherer Wert zurückgegeben wird, als bei denen die Werte im Dictionary haben. Beispiel:

Code: Alles auswählen

    dic_full = {'field4': 40, 'field2': 20, 'field1': 30, 'field3': 10}
    parts = ['field2', 'field4', 'field3', 'field5']
    
    def key_func(item):
        try:
            return (0, dic_full[item])
        except KeyError:
            return (1, None)
    
    parts.sort(key=key_func)
    print parts
Ansonsten solltest Du `list.remove()` so nicht in einer Schleife verwenden. Das wäre nicht nur ineffizient, sondern funktioniert auch nicht richtig. Wenn Du Elemente aus einer Liste entfernst, über die Du gerade iterierst, dann rutschen ja alle Folge-Elemente einen Platz nach vorne. Davon bekommt aber die Schleife nichts mit und es werden Elemente ungeprüft übersprungen.
rads
User
Beiträge: 153
Registriert: Freitag 26. März 2010, 15:51

@BlackJack Nochmals vielen Dank.

Ich habe es jetzt über list comprehension gemacht, fande ich dann eine zumindest optisch schön schlanke Lösung.

Code: Alles auswählen

    dicFull = {'field4':40,'field2':20,'field1':30,'field3':10}
    partList = ['field2','field4','field3','field5']
    tmpList = [  x for x in partList if x not in dicFull.keys()]
    partList = [ x for x in partList if x not in tmpList]
    partList.sort( key=dicFull.__getitem__)
    partList = partList + tmpList
    print partList
ist ja an sich dann nicht mehr ganz so schrecklich?
BlackJack

Immer noch schrecklich. In der ersten "list comprehension" (LC) wird für jedes Element in der Liste eine Liste mit den Schlüsseln des Dictionaries erzeugt und in dem linear gesucht und in der zweiten LC werden Elemente linear in der Liste von der ersten LC gesucht. Effizient ist das nicht gerade.

Edit: So wird die `parts`-Liste nur einmal durchlaufen und auch effizient im Dictionary gesucht:

Code: Alles auswählen

    dic_full = {'field4': 40, 'field2': 20, 'field1': 30, 'field3': 10}
    parts = ['field2', 'field4', 'field3', 'field5']
    
    sortable_items = list()
    remaining_items = list()
    for item in parts:
        (sortable_items if item in dic_full else remaining_items).append(item)
    sortable_items.sort(key=dic_full.__getitem__)
    parts = sortable_items + remaining_items
    print parts
rads
User
Beiträge: 153
Registriert: Freitag 26. März 2010, 15:51

Danke für die Anregungen BlackJack. Wurde berücksichtigt.

Anbei eine Variation und weil mich die Lösung von BlackJack interessiert hat.

Sortierung einer Tupe-Liste anhand einer Referenz-Liste wobei auch nicht alle
Werte in der Referenzliste vorhanden sein müssen

Falls es wer mal brauchen kann bzw. so wie ich nicht auf anhieb drauf kommt.

Code: Alles auswählen

orderList = ['nr4', 'nr2', 'nr3', 'nr1']
    sqlMap = [('nr1', u'0'), ('nr5', u'blubb'), ('nr3', 25)]
    
    def key_func(item):
        try:
            return (0, orderList.index(item[0]))
        except Exception:
            return (1, None)
        
   
    sqlMap.sort(key=key_func)

    print sqlMap
Grüße Stefan
Benutzeravatar
mkesper
User
Beiträge: 919
Registriert: Montag 20. November 2006, 15:48
Wohnort: formerly known as mkallas
Kontaktdaten:

Code: Alles auswählen

except Exception
ist eine schreckliche Idee!
Barabbas
User
Beiträge: 349
Registriert: Dienstag 4. März 2008, 14:47

Ich habe gehört, man spricht in diesem Fall auch von "Pokeman-Exceptions" ("Catch 'em all!") :wink:
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

mkesper hat geschrieben:

Code: Alles auswählen

except Exception
ist eine schreckliche Idee!
Na immerhin besser als ein blankes `except`.
@rads: Warum die Faulheit? `ValueError` ist nicht sonderlich laenger.
rads
User
Beiträge: 153
Registriert: Freitag 26. März 2010, 15:51

@cofi

naja ich bin javaverwöhnt in kombination von eclipse, da ist die Refactoringfunktionaliät, naja sagen wir mal ausgeprägter, als bei Pydev.
An sich liegt es daran, das er bei der automatischen generierung des try:except: Blockes Exception schreibt,und nicht die
eigentlich möglichen auftretenden Exceptions. Ka wo ich das einstellen kann, aber ja es ist wohl schlichte Faulheit.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

rads hat geschrieben:Ka wo ich das einstellen kann, aber ja es ist wohl schlichte Faulheit.
Nein, das lässt sich nicht statisch ermitteln. Jedenfalls ist das so keine gute Einstellung.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Antworten