Seite 1 von 1

Liste mit Schleife lesen

Verfasst: Sonntag 3. November 2019, 00:15
von Speedy
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?

Re: Liste mit Schleife lesen

Verfasst: Sonntag 3. November 2019, 02:37
von Squipy
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] )
        

Re: Liste mit Schleife lesen

Verfasst: Sonntag 3. November 2019, 05:57
von __blackjack__
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.

Re: Liste mit Schleife lesen

Verfasst: Sonntag 3. November 2019, 11:55
von ThomasL
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}

Re: Liste mit Schleife lesen

Verfasst: Sonntag 3. November 2019, 15:50
von Speedy

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

Re: Liste mit Schleife lesen

Verfasst: Sonntag 3. November 2019, 16:48
von __blackjack__
@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])``.