liste 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: 63
Registriert: Dienstag 4. März 2014, 12:04

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?
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

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

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.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@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']
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
/me
User
Beiträge: 3554
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Beginnen die Einzelwerte immer mit "4-" oder muss man das auch noch als zweites Kriterium bei der Sortierung berücksichtigen?
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

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))))))
karolus
User
Beiträge: 140
Registriert: Samstag 22. August 2009, 22:34

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)))
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Weil ich einen nicht allzu umständlichen, aber dennoch halbwegs kryptischen "one liner" haben wollte. Viel Spaß bei der Suche nach anderen Varianten.
Benutzeravatar
DeaD_EyE
User
Beiträge: 1012
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

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")
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

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)),
    )
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten