Seite 1 von 1

liste sortieren

Verfasst: Montag 3. Oktober 2022, 11:07
von blutigeranfaenger
Hallo zusammen,
ich möchte gerne diese Liste

Code: Alles auswählen

names = "4-1, 4-2, 4-4, 4-5, 4-6, 4-3, 4-11, 4-13, 4-14, 4-16,4-12, 4-10, 4-7, 4-Z15, 4-8, 4-9 ".split()
nach den Zahlen die nach dem Minus bzw. Z kommen sortieren. Das Z soll bei der Sortierung keine Rolle spielen
also:

Code: Alles auswählen

names_sortiert = ["4-1","4-2", .... "4-Z15", "4-16"]
Weiß jemand, wie man das machen kann?

Re: liste sortieren

Verfasst: Montag 3. Oktober 2022, 11:24
von Sirius3
Du hast vergessen zu erklären, was mit dem Komma passieren soll.
Wenn man vor einem Problem steht, dann versucht man es erst in Teilprobleme zu zerlegen, bis man die Einzelteile trivial lösen kann.
Erster Schritt wäre also, erst den String in eine Liste umzuwalnden, dann eine Funktion schreiben, die den gewünschten Teil in eine Zahl umwandelt, und dann kann man mit hilfe dieser Zahl die Liste sortieren.
Was davon hast Du schon probiert umzusetzen und wo kommst Du konkret nicht weiter?

Re: liste sortieren

Verfasst: Montag 3. Oktober 2022, 11:45
von blutigeranfaenger
Hallo zusammen,
ja, das Komma gehört da nicht rein.
Danke schon mal für den Tipp. Ich probiere es gleich, wie Du gesagt hast.

Re: liste sortieren

Verfasst: Montag 3. Oktober 2022, 15:31
von __blackjack__
@blutigeranfaenger: Wenn Du Beispiele zeigst, wäre es besser wenn die korrekt wären. Also nicht nur, dass die Kommas da nicht rein gehören, an einer Stelle fehlt wohl auch ein Leerzeichen:

Code: Alles auswählen

In [480]: "4-1, 4-2, 4-4, 4-5, 4-6, 4-3, 4-11, 4-13, 4-14, 4-16,4-12, 4-10, 4-7, 4-Z15, 4-8, 4-9 ".split()
Out[480]:['4-1,',
 '4-2,',
 '4-4,',
 '4-5,',
 '4-6,',
 '4-3,',
 '4-11,',
 '4-13,',
 '4-14,',
 '4-16,4-12,',
 '4-10,',
 '4-7,',
 '4-Z15,',
 '4-8,',
 '4-9']

Re: liste sortieren

Verfasst: Montag 3. Oktober 2022, 16:21
von /me
Beginnen die Einzelwerte immer mit "4-" oder muss man das auch noch als zweites Kriterium bei der Sortierung berücksichtigen?

Re: liste sortieren

Verfasst: Montag 3. Oktober 2022, 16:25
von kbr
Das ist in der Tat ein recht ungünstiges Format, lässt sich aber lösen (ohne Berücksichtigung der Frage von /me) . Ich vermute jedoch, dass die folgende Lösung nicht für blutige Anfänger geeignet ist ;)

Code: Alles auswählen

import re
names = "4-1, 4-2, 4-4, 4-5, 4-6, 4-3, 4-11, 4-13, 4-14, 4-16,4-12, 4-10, 4-7, 4-Z15, 4-8, 4-9 "
print(list(map(str.strip, sorted(names.split(","), key=lambda x: int(re.search(r"-.*?(\d+)", x).group(1))))))

Re: liste sortieren

Verfasst: Montag 3. Oktober 2022, 17:08
von karolus
Wenn denn schon re gebraucht wird, warum nicht gleich:

Code: Alles auswählen

import re

d_d_rex = re.compile(r'(\d+-\D*?)(\d+)')

def last_int(entry):
    return int(entry[-1])

names = d_d_rex.findall("4-1, 4-2, 4-4, 4-5, 4-6, 4-3, 4-11, 4-13, 4-14, 4-16,4-12, 4-10, 4-7, 4-Z15, 4-8, 4-9 ")
    
list(map("".join, sorted(names,key=last_int)))

Re: liste sortieren

Verfasst: Montag 3. Oktober 2022, 17:22
von kbr
Weil ich einen nicht allzu umständlichen, aber dennoch halbwegs kryptischen "one liner" haben wollte. Viel Spaß bei der Suche nach anderen Varianten.

Re: liste sortieren

Verfasst: Dienstag 4. Oktober 2022, 18:55
von DeaD_EyE
kbr hat geschrieben: Montag 3. Oktober 2022, 17:22 Viel Spaß bei der Suche nach anderen Varianten.
Bloß kein Regex Golf...

Anfänger sollten anfangs Regex meiden und sich mehr auf die Methoden der Klasse str konzentrieren. Da sind ganz nützliche Methoden dabei.
Falls man darüber nachdenkt, sich Zeichenketten aus A-Z zusammenzusetzen, dann lieber das Modul string importieren.
Mehr dazu weiter unten.

Oft will man ein Problem mit Regex lösen und hat danach zwei Probleme.

Beispiel ohne Regex:

Code: Alles auswählen

names = "     4-1, 4-2, 4-4, 4-5, 4-6 , 4-3, 4-11   , 4-13, 4-14, 4-16,4-12, 4-10, 4-7, 4-Z15    , 4-8, 4--9    "


def sorted_by_second(text):
    def key(value: str):
        return int(value.partition("-")[2].replace("Z", ""))

    splitter_stripper = map(str.strip, names.split(","))
    return ",".join(
        sorted(
            splitter_stripper,
            key=key,
        )
    )


print(sorted_by_second(names))
Das Ungewöhnliche hier ist die Funktion in der Funktion. Sofern die Key-Funktion nirgendwo anders benötigt wird, ist das eine Möglichkeit den Code etwas leserlicher zu schreiben und dennoch eine Isolation zur Modulebene zu haben. Hat man hingegen ganz viele andere Funktionen, die dieselbe Key-Funktion benötigen, dann sollte die Funktion auf Modulebene packen. Der Name sollte dann nicht key sein, da Verwechslungsgefahr besteht (häufiger Name) und man später aus Versehen ein anderes Objekt dem Namen "key" zuweisen könnte, ohne es zu bemerken. Diese Fehler kommen häufig vor. Wäre die Funktion `sorted_by_second` länger, sollte auch dann ein anderer Name für die Funktion `key` verwendet werden.

Code: Alles auswählen

def key():
    """
    Eine wichtige Funktion
    """
    pass
    
# 10_000 Zeilen Code

for key in range(10):
    pass

# 100 Zeilen Code

# jetzt die Wichtige Funktion aufrufen:
key()

# TypeError: 'int' object is not callable
Erst die Funktion key definiert (Funktionsobjekt wird dem Namen key zugewiesen).
In der for-Scheife werden dann dem Namen key die resultierenden int von range zugewiesen.
Dadurch ist dann key == 9

Der Aufruf von key führt dann letztlich zum Fehler. Eigentlich will man die Funktion key aufrufen, aber key ist schon lange ein int.

Nun weiter im Text:
Der Aufruf der Sortier-Funktion:

Code: Alles auswählen

sorted(
    splitter_stripper,
    key=key,
)

Zuerst wird der String beim , gesplittet und für jedes resultierende Element (str) wird dann die Methode str.strip angewandt, die links und rechts eine Menge von definierten Leerzeichen entfernt (unter anderem auch Tabulator siehe: string.whitespace).

Code: Alles auswählen

splitter_stripper = map(str.strip, names.split(","))

Ich vermute mal, dass der Bindestrich - nur das Trennzeichen ist und die Werte alle positiv sind.
Falls Werte negativ sind, sollten es zwei Bindestriche sein.

Falls andere Buchstaben als Z drin vorkommen, gibt es einen ValueError.

Man kann auch eine Menge von Zeichen am Anfang eines Strings (Z15) mit der Methode lstrip entfernen.
Dann wird die Zeichenkette von links nach rechts so lange gekürzt, bis ein Zeichen vorkommt, das nicht in der Menge enthalten ist.

Beispiel:

Code: Alles auswählen

from string import ascii_uppercase

"B15".lstrip(ascii_uppercase)
# 15

"ZAB16".lstrrip(ascii_uppercase)
# 16
Achtung: strip, lstrip und rstrip wird oft missverstanden. Deswegen schrieb ich auch explizit Menge, da die Reihenfolge keine Rolle spielt.

Code: Alles auswählen

leer = "anna".lstrip("na")

Re: liste sortieren

Verfasst: Dienstag 4. Oktober 2022, 19:14
von __blackjack__
Ich würde `re` verwenden und einfach nach den letzten Ziffern suchen wenn nicht wirklich klar ist, wie das davor aussehen kann:

Code: Alles auswählen

def split_and_sort(text):
    return sorted(
        (name.strip() for name in names.split(",")),
        key=lambda name: int(re.search(r"(\d+)$", name).group(1)),
    )