Seite 1 von 1

wörterbuch auf bestimmte art sortieren

Verfasst: Mittwoch 1. November 2023, 13:54
von blutigeranfaenger
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.

Re: wörterbuch auf bestimmte art sortieren

Verfasst: Mittwoch 1. November 2023, 14:22
von __blackjack__
@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.

Re: wörterbuch auf bestimmte art sortieren

Verfasst: Mittwoch 1. November 2023, 14:58
von blutigeranfaenger
oh, das klingt nicht gerade einfach, wenn man den Sortier-Schlüssel erstellen will.

Re: wörterbuch auf bestimmte art sortieren

Verfasst: Mittwoch 1. November 2023, 16:10
von kbr
@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.

Re: wörterbuch auf bestimmte art sortieren

Verfasst: Mittwoch 1. November 2023, 16:20
von snafu
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.

Re: wörterbuch auf bestimmte art sortieren

Verfasst: Mittwoch 1. November 2023, 16:48
von __blackjack__
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“.

Re: wörterbuch auf bestimmte art sortieren

Verfasst: Mittwoch 1. November 2023, 16:54
von kbr
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.

Re: wörterbuch auf bestimmte art sortieren

Verfasst: Mittwoch 1. November 2023, 17:04
von snafu
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.

Re: wörterbuch auf bestimmte art sortieren

Verfasst: Mittwoch 1. November 2023, 21:38
von DeaD_EyE

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.