wörterbuch auf bestimmte art sortieren

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
blutigeranfaenger
User
Beiträge: 65
Registriert: Dienstag 4. März 2014, 12:04

Hallo zusammen,
ich möchte folgendes Wörterbuch sortieren:

Code: Alles auswählen

pcs_fortenames = { 
(0,1,2,3):"4-1",
(0,1,4,6):"4-Z15",
(0,1,3,4):"4-3",
(0,1,2,4):"4-2",
(0,1,2,5):"4-4",
(0,1,2,6):"4-5",
(0,1,2,7):"4-6",
(0,2,3,6):"4-12",
(0,1,4,5):"4-7",
(0,1,5,6):"4-8",
(0,1,6,7):"4-9",
(0,2,4,6):"4-21",
(0,3,4,7):"4-17",
(0,2,3,5):"4-10",
(0,1,3,6):"4-13",
(0,2,3,7):"4-14",
(0,1,5,7):"4-16",
(0,1,4,7):"4-18",
(0,1,4,8):"4-19",
(0,1,5,8):"4-20",
(0,2,4,7):"4-22",
(0,2,5,7):"4-23",
(0,2,4,8):"4-24",
(0,2,6,8):"4-25",
(0,3,5,8):"4-26",
(0,2,5,8):"4-27",
(0,3,6,9):"4-28",
(0,1,3,7):"4-Z29"
}
Und zwar nach möchte ich nach den Values sortieren., und zwar so, dass das Tupel mit dem value 4-1 zuerst erscheint, dann 4-2, 4-3, etc. 4-Z15 soll bitte nach 4-14 erscheinen. Wie kann ich das erreichen?
Leider ergibt sortedDict = pcs_fortenames(alles.values()) etwas ganz anderes, da erscheint nach 4-1 4-11, usw.
Benutzeravatar
__blackjack__
User
Beiträge: 14052
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@blutigeranfaenger: ``sortedDict = pcs_fortenames(alles.values())`` sollte einen TypeError geben weil Wörterbücher nicht aufrufbar sind.

Wenn da wieder ein Wörterbuch bei heraus kommen soll, musst Du ein neues erstellen mit den Schlüssel/Wert-Paaren in der sortierten Reihenfolge. Und für das sortieren eine Funktion schreiben die aus einem Schlüssel/Wert-Paar einen Wert berechnet nach dem das Paar sortiert werden kann, wenn diese Funktion für jedes Paar aufgerufen wird. Also den Sortierschlüssel. Das ist dann für das `key`-Argument von der `sorted()`-Funktion.

Wahrscheinlich läuft das auf ein Tupel hinaus, welches die Zahlen aus den momentanen Werten des Wörterbuchs enthält und vielleicht einen Wahrheitswert ob ein "Z" enthalten sein kann oder nicht, damit solche Werte auch an der richtigen Stelle einsortiert werden. Plus die den Schlüssel um gleiche Werte irgendwie auflösen zu können, denn die Werte müssen ja im Gegensatz zu Schlüsseln nicht einmalig sein. Es sei denn man kann das ausschliessen. Aber auch dann würde ich das immer noch mit dazu packen, damit man im Fehlerfall das doch mal Werte doppelt vorkommen, eine konsistente Sortierung hat.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
blutigeranfaenger
User
Beiträge: 65
Registriert: Dienstag 4. März 2014, 12:04

oh, das klingt nicht gerade einfach, wenn man den Sortier-Schlüssel erstellen will.
Benutzeravatar
kbr
User
Beiträge: 1508
Registriert: Mittwoch 15. Oktober 2008, 09:27

@blutigeranfaenger: das könnte man wie folgt angehen, da sorted Tuple mit numerischen Inhalten sortieren kann:

Code: Alles auswählen

def nameconvert(values):
    i, j = values[-1].split("-")
    j = float(j[1:]) + 0.5 if j.startswith("Z") else float(j)
    return int(i), j

dict(sorted(pcs_fortenames.items(), key=nameconvert))
Geht vielleicht auch eleganter.
Benutzeravatar
snafu
User
Beiträge: 6867
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Geht auch mit einem regulären Ausdruck:

Code: Alles auswählen

import re

def sort_by_values(mapping):
    match = re.compile(r"(\d+)-(Z)?(\d+)").match
    def keyfunc(item):
        key, value = item
        if (m := match(value)) is None:
            return ()
        return int(m.group(1)), bool(m.group(2)), int(m.group(3))
    return dict(sorted(mapping.items(), key=keyfunc))
Und dahin das Dict übergeben.
Benutzeravatar
__blackjack__
User
Beiträge: 14052
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Wobei bei solchen Sachen oft auch die Frage Sinn macht was das eigentlich für Zeichenketten sind, die dort als Werte verwendet werden und ob das wirklich Zeichenketten sein müssen wenn die eigentlich strukturierte Daten enthalten. Also ob das nicht besser ein eigener Datentyp mit entsprechenden Eigenschaften wäre während diese Werte im Programm verarbeitet werden. Da könnte man sich vielleicht sogar eine `key`-Funktion sparen wenn die Werte von diesem Typ eine ”natürliche” Ordnung hätten die man den Objekten selbst beibringen kann.

@snafu: Wäre `fullmatch()` nicht besser als `match()`? Und ich würde wie gesagt `key` noch integrieren als „tie breaker“.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Benutzeravatar
kbr
User
Beiträge: 1508
Registriert: Mittwoch 15. Oktober 2008, 09:27

Wenn die zu sortierenden Einträge eigene Datentypen wären, wäre das in der Tat am elegantesten.

@snafu: bei deiner Variante werden die Einträge mit "Z" falsch sortiert.
Benutzeravatar
snafu
User
Beiträge: 6867
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Ja stimmt, die zweite Gruppe müsste in der Anordnung für den vergleichenden Schlüssel nach hinten. Und dann könnte man auch die leere Zeichenkette als Ersatz für None benutzen, wenn die Gruppe nicht matcht, sowie das Zeichen im Original (vielleicht gibt es andere als Z), wenn sie matcht. Alle Eventualitäten einzuplanen, wird dann wieder so richtig "lustig". Eine vernünftige Struktur der ursprünglichen Daten wäre viel besser, wie ja schon geschrieben wurde.
Benutzeravatar
DeaD_EyE
User
Beiträge: 1240
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Code: Alles auswählen

pcs_fortenames = {
    (0, 1, 2, 3): "4-1",
    (0, 1, 4, 6): "4-Z15",
    (0, 1, 3, 4): "4-3",
    (0, 1, 2, 4): "4-2",
    (0, 1, 2, 5): "4-4",
    (0, 1, 2, 6): "4-5",
    (0, 1, 2, 7): "4-6",
    (0, 2, 3, 6): "4-12",
    (0, 1, 4, 5): "4-7",
    (0, 1, 5, 6): "4-8",
    (0, 1, 6, 7): "4-9",
    (0, 2, 4, 6): "4-21",
    (0, 3, 4, 7): "4-17",
    (0, 2, 3, 5): "4-10",
    (0, 1, 3, 6): "4-13",
    (0, 2, 3, 7): "4-14",
    (0, 1, 5, 7): "4-16",
    (0, 1, 4, 7): "4-18",
    (0, 1, 4, 8): "4-19",
    (0, 1, 5, 8): "4-20",
    (0, 2, 4, 7): "4-22",
    (0, 2, 5, 7): "4-23",
    (0, 2, 4, 8): "4-24",
    (0, 2, 6, 8): "4-25",
    (0, 3, 5, 8): "4-26",
    (0, 2, 5, 8): "4-27",
    (0, 3, 6, 9): "4-28",
    (0, 1, 3, 7): "4-Z29",
}



def keyfunc(item):
    values = item.split("-", maxsplit=1)
    if values[1].startswith("Z"):
        values = (values[0], values[1].removeprefix("Z"), 1)
    return tuple(map(int, values))


result = sorted(pcs_fortenames.values(), key=keyfunc)
print(result)

Code: Alles auswählen

['4-1', '4-2', '4-3', '4-4', '4-5', '4-6', '4-7', '4-8', '4-9', '4-10', '4-12', '4-13', '4-14', '4-Z15', '4-16', '4-17', '4-18', '4-19', '4-20', '4-21', '4-22', '4-23', '4-24', '4-25', '4-26', '4-27', '4-28', '4-Z29']
Wenn ein anderer Buchstabe als "Z" verwendet wird, müsste es einen ValueError geben, da die Strings nicht in einen Integer umgewandelt werden können.

PS: Im Code ist irgendwo noch ein Fehlehr. Aber nach 10 Stunden Arbeit und 5 Stunden Autofahrt habe ich kein Bock mehr.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Antworten