Liste mit Schleife lesen

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
Antworten
Speedy
User
Beiträge: 11
Registriert: Mittwoch 4. September 2019, 11:29

Hallo,
ich habe eine kleine Gedankenblockade. Mein Code funktioniert nicht so, wie es funktionieren sollte.

Ich habe z.B folgende Liste:

Code: Alles auswählen

a = ["A", "A.1", "A.2", "B", "C", "C.1", "C.2"]
Mein Ziel ist es, den Anfangs- und Endindex von den selben Buchstaben zu bekommen.
Z.B.:
A = [0,2]
B = [3]
C = [4,6]

Daher habe ich zuerst versucht, den Endindex herauszufinden:

Code: Alles auswählen

for i in range(len(a)-1):
    if a[i].rsplit(".",1)[0] == a[i+1].rsplit(".",1)[0]:
        i += 1
    else:
        print(i)
Das Ergebnis, dass ich hier gerne hätte wäre (für i): 2,3,6
Allerdings hört die Schleife bei der vorletzten Buchstabe auf, sodass ich für das letzte Element in der Liste kein Index bekomme.
Wo ist denn mein Gedankenfehler?
Squipy
User
Beiträge: 39
Registriert: Sonntag 30. Juni 2019, 16:42

guck dir diesen output mal an, evtl. wird die damit klarer was da passiert:

Code: Alles auswählen

a = ["A", "A.1", "A.2", "B", "C", "C.1", "C.2"]


for i in range(len(a)-1):
    if a[i].rsplit(".",1)[0] == a[i+1].rsplit(".",1)[0]:
       print(i,": ", a[i], " same start index: ", a[i+1] )
       
    else:
        print(i,": ", a[i], " not same start index: ", a[i+1] )
        
Benutzeravatar
__blackjack__
User
Beiträge: 13925
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Eine Lösung die etwas weniger Ansprüche an die Eingabe stellt: Beliebiges iterierbares Objekt statt Sequenz mit Indexzugriff.

Code: Alles auswählen

#!/usr/bin/env python3
from itertools import groupby

from more_itertools import ilen


def get_ranges(items):
    start_index = 0
    for first_component, group in groupby(items, lambda s: s.split(".", 1)[0]):
        end_index = start_index + ilen(group) - 1
        yield (
            first_component,
            (
                (start_index,)
                if start_index == end_index
                else (start_index, end_index)
            ),
        )
        start_index = end_index + 1


def main():
    print(list(get_ranges(["A", "A.1", "A.2", "B", "C", "C.1", "C.2"])))


if __name__ == "__main__":
    main()
Ausgabe:

Code: Alles auswählen

[('A', (0, 2)), ('B', (3,)), ('C', (4, 6))]
Ein bisschen unschön finde ich die Asymmetrie bei den Werten im Ergebnis, also das es Werte mit zwei Elementen und Werte mit einem Element gibt. So etwas führt in der Regel beim weiterverarbeitenden Code zu mehr Fallunterscheidungen und damit mehr Komplexität. Selbst beim Erzeugen musste man deshalb schon eine Fallunterscheidung machen. So etwas zieht sich dann gerne mal an mehreren Stellen durch das ganze Programm.
“Java is a DSL to transform big Xml documents into long exception stack traces.”
— Scott Bellware
Benutzeravatar
ThomasL
User
Beiträge: 1377
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Was haltet ihr denn hiervon?

Code: Alles auswählen

from collections import defaultdict

elements = ["A", "A.1", "A.2", "B", "C", "C.1", "C.2"]

dictionary = defaultdict(list)

for index, item in enumerate(elements):
    dictionary[item[0]].append(index)

for key, value in dictionary.items():
    print(key, {min(value)} | {max(value)})
Output:

Code: Alles auswählen

A {0, 2}
B {3}
C {4, 6}
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Speedy
User
Beiträge: 11
Registriert: Mittwoch 4. September 2019, 11:29

Code: Alles auswählen

guck dir diesen output mal an, evtl. wird die damit klarer was da passiert:

Ich blicke immernoch nicht durch, warum es nicht funktioniert...

@blackjack und @ThomasL danke für eure Vorschläge! Auf diese Ansätze wäre ich selber nie gekommen :O
Benutzeravatar
__blackjack__
User
Beiträge: 13925
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@ThomasL: Das mit den Mengen am Ende geht mir ein bisschen zu sehr in Richtung Code-Golf. Das sieht nach einer Lösung aus bei der komplizierte Sachen gemacht werden um ein paar Zeichen zu sparen. Mindestens mal `min()` und `max()` sind überflüssig, weil wir ja *wissen* das die Werte die dabei heraus kommen *immer* an Index 0 und -1 stehen. Dazu muss man nicht zweimal alle Indizes durchiterieren. Also statt ``{min(value)} | {max(value)}`` mit zwei temporären `set`\s die genau *ein* Element enthalten eher ``{value[j] for j in [0, -1]}``. Daran stört mich aber immer noch diese Asymmetrie und das man sich auf die Ordnung von den Elementen einer Menge verlassen muss die ja noch nicht allzu lange garantiert ist in Python. Ich würde da nach wie vor einfach ein Tupel mit beiden Angaben bevorzugen: ``(value[0], value[-1])``.
“Java is a DSL to transform big Xml documents into long exception stack traces.”
— Scott Bellware
Antworten