Liste wieder und wieder durchlaufen bis die Anzahl der zurückgegebenen Elemente stimmt

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.
Atalanttore
User
Beiträge: 129
Registriert: Freitag 6. August 2010, 17:03

Sonntag 1. Juli 2018, 16:28

Hallo

Ich würde gerne die Elemente einer Liste mit 12 Einträgen immer wieder durchlaufen. Sobald das Ende der Liste erreicht ist, sollte der Durchlauf wieder von vorne beginnen, aber insgesamt sollen nur 1000 Werte ausgegeben werden. Die Liste müsste also 83 mal komplett durchlaufen und beim 84. Durchlauf beim 4. Element abgebrochen werden.

Bietet Python eine passende Funktion dafür an?

Gruß
Atalanttore
Sirius3
User
Beiträge: 8647
Registriert: Sonntag 21. Oktober 2012, 17:20

Sonntag 1. Juli 2018, 16:33

Aus dem Modul itertools, cycle und islice.
nezzcarth
User
Beiträge: 574
Registriert: Samstag 16. April 2011, 12:47

Sonntag 1. Juli 2018, 17:07

Eine mögliche Variante:

Code: Alles auswählen

In [1]: from itertools import cycle

In [2]: def repeat(items, limit):
   ...:     items = cycle(items)
   ...:     for i in range(limit):
   ...:         yield next(items)
   ...:         

In [3]: l = [1,2,3]

In [4]: list(repeat(l, 5))
Out[4]: [1, 2, 3, 1, 2]
Benutzeravatar
__blackjack__
User
Beiträge: 1460
Registriert: Samstag 2. Juni 2018, 10:21

Sonntag 1. Juli 2018, 17:12

@nezzcarth: Aber es gibt doch `islice()`, warum programmierst Du das noch mal in abgespeckter Form nach und benennst das dann auch noch wie eine andere Funktion aus `itertools` die etwas anderes macht?

Code: Alles auswählen

In [174]: l = [1,2,3]

In [175]: list(islice(cycle(l), 5))
Out[175]: [1, 2, 3, 1, 2]

Code: Alles auswählen

    **** COMMODORE 64 BASIC V2 ****
 64K RAM SYSTEM  38911 BASIC BYTES FREE
   CYBERPUNX RETRO REPLAY 64KB - 3.8P
READY.
█
Benutzeravatar
ThomasL
User
Beiträge: 385
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Sonntag 1. Juli 2018, 17:23

Eine interessante Variante kann man mit einem Generator bauen:
Edit: meine Eingabe hat sich mit obigen Antworten überschnitten, hier ein schöner handgestrickter Generator, ohne import schnickschnack

Code: Alles auswählen

def my_generator(my_list, count):
    counter = count + 1
    while counter > 0:
        for item in my_list:
            counter -= 1
            if counter > 0:
                yield item

output = my_generator([1,2,3,4,5,6,7,8,9,10,11,12], 1000)

for i in range(1000):
    print(f'{next(output)} ', end='')
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
nezzcarth
User
Beiträge: 574
Registriert: Samstag 16. April 2011, 12:47

Sonntag 1. Juli 2018, 17:27

@__blackjack__: Offensichtlich, weil ich es nicht besser wusste ;) (an islice habe ich nicht gedacht und außer cycle oder repeat wüsste ich nicht, wie man es groß anders nennen soll; repeat wird ja zumindest nicht verwendet).
Benutzeravatar
ThomasL
User
Beiträge: 385
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Sonntag 1. Juli 2018, 17:34

__blackjack__ hat geschrieben:
Sonntag 1. Juli 2018, 17:12

Code: Alles auswählen

In [174]: l = [1,2,3]
In [175]: list(islice(cycle(l), 5))
Out[175]: [1, 2, 3, 1, 2]
Verstehe ich diese Lösung so, dass hier eine Liste mit 1000 Elementen erzeugt wird, über die man dann iterieren muss?
Wenn ja, nicht sehr ökonomisch.
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
nezzcarth
User
Beiträge: 574
Registriert: Samstag 16. April 2011, 12:47

Sonntag 1. Juli 2018, 17:36

islice gibt einen Iterator zurück. Die Umwandlung in eine Liste war zumindest in meinem Beispiel (das __blackjack__ verbessert hat) nur zur Illustration gedacht; eine Schleife mit einem Dummy-Print nimmt mehr Platz weg.
Sirius3
User
Beiträge: 8647
Registriert: Sonntag 21. Oktober 2012, 17:20

Sonntag 1. Juli 2018, 17:54

@ThomasL: Import-Schnickschnack ist genau dafür da, dass man nicht jeden Bling selbst schreiben muß. Nicht sehr ökonomisch ist an Deiner Lösung, dass die Liste immer komplett durchlaufen wird. Schönheit definiert ja jeder anders, z.B. die for-range-Schleife.
Atalanttore
User
Beiträge: 129
Registriert: Freitag 6. August 2010, 17:03

Sonntag 1. Juli 2018, 18:20

Danke für die vielen Antworten.

Gruß
Atalanttore
Benutzeravatar
ThomasL
User
Beiträge: 385
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Sonntag 1. Juli 2018, 18:22

@Sirius3 Du hast die ursprüngliche Fragestellung gelesen?
Atalanttore hat geschrieben:
Sonntag 1. Juli 2018, 16:28
Hallo, Ich würde gerne die Elemente einer Liste mit 12 Einträgen immer wieder durchlaufen. Sobald das Ende der Liste erreicht ist, sollte der Durchlauf wieder von vorne beginnen, aber insgesamt sollen nur 1000 Werte ausgegeben werden. Die Liste müsste also 83 mal komplett durchlaufen und beim 84. Durchlauf beim 4. Element abgebrochen werden.
Bietet Python eine passende Funktion dafür an? Gruß Atalanttore
Was stört dich jetzt bitte an meinem Beispiel Ausgabecode, dass er alle Elemente ausgibt? Hä??

Ich habe einen konfigurierbaren Generator, die Liste die immer wieder durchlaufen werden soll
und die Anzahl der Werte die ausgegeben werden sollen können angegeben werden.

Die for-schleife ist nur ein Beispiel um zu zeigen, wie man jetzt die einzelnen Werte (in dem Beispiel mit next() ) abruft.

Selbstverständlich ist diese Lösung hier eleganter:

Code: Alles auswählen

for item in output:
    print(f'{item} ', end='')
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
Benutzeravatar
kbr
User
Beiträge: 950
Registriert: Mittwoch 15. Oktober 2008, 09:27

Sonntag 1. Juli 2018, 18:28

@ThomasL: Wenn es Dir um Ökonomie geht, dann nimm:

Code: Alles auswählen

for n in islice(cycle(range(12), 1000):
    ...
Sicher sind eigene Generatoren schön, aber noch schöner ist es, wenn man sich bereits der builtins und aus der Standard-Library bedienen kann.
Benutzeravatar
__blackjack__
User
Beiträge: 1460
Registriert: Samstag 2. Juni 2018, 10:21

Sonntag 1. Juli 2018, 19:19

@ThomasL: Bei Deiner Lösung stört, dass die Liste auch in den Fällen komplett durchlaufen wird wo gar nicht alle Elemente benötigt werden. Wenn man 1000 Elemente übergibt und 1005 haben möchte, wird die ``for``-Schleife *in* der Funktion 2000 mal durchlaufen. Das sind 1995 mal mehr als nötig wären. Klar kann man das jetzt fixen — man kann aber auch einfach `cycle()` und `islice()` nehmen. Die Funktionen in `itertools` sind ja genau dafür gemacht das man die benutzen und kombinieren kann/soll, um das Rad nicht immer wieder neu zu erfinden, und dann nicht ganz rund sondern mit Ecken und Kanten und wenn man Pech hat auch mit Sollbruchstellen. `cycle()` kann zudem nicht nur mit Sequenztypen, sondern mit allen iterierbaren Objekten.

Code: Alles auswählen

    **** COMMODORE 64 BASIC V2 ****
 64K RAM SYSTEM  38911 BASIC BYTES FREE
   CYBERPUNX RETRO REPLAY 64KB - 3.8P
READY.
█
Benutzeravatar
ThomasL
User
Beiträge: 385
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Sonntag 1. Juli 2018, 19:51

__blackjack__ hat geschrieben:
Sonntag 1. Juli 2018, 19:19
@ThomasL: Bei Deiner Lösung stört, dass die Liste auch in den Fällen komplett durchlaufen wird wo gar nicht alle Elemente benötigt werden.
Sorry aber dies kann ich nicht nachvollziehen, du weißt was ein Generator ist?
Bei jedem Abruf durch next() oder bei for item in wird EIN Element zurück gegeben.
Wenn ich keine Elemente abrufe wird auch nichts durchlaufen
Wenn man 1000 Elemente übergibt und 1005 haben möchte
Was ist denn das für nen Quatsch.
Wenn man 1005 Elemente haben möchte, dann übergibt man den Wert 1005 und nicht 1000.
Und es werden auch keine 1000 Elemente übergeben. Hast du die Generatorfunktion my_generator überhaupt verstanden?
Der Funktion wird die Liste deren einzelne Elemente nacheinander und nach kompletten Durchlauf wieder von vorne an
ausgegeben werden sollen und die Anzahl der Elemente die maximale ausgegeben werden sollen, übergeben.
wird die ``for``-Schleife *in* der Funktion 2000 mal durchlaufen. Das sind 1995 mal mehr als nötig wären.
auch diesen Murks musst du mir mal genauer erklären.
Die for-Schleife iteriert über die Elemente der übergebenen Liste, und mehr nicht.
Lass diesen Code hier laufen und dann überlege dir eine Erklärung

Code: Alles auswählen

def my_generator(my_list, count):
    counter = count + 1
    while counter > 0:
        print(f'Counter:{counter}')  # eingefügt
        for item in my_list:
            counter -= 1
            if counter > 0:
                yield item

output = my_generator([1,2,3,4,5,6,7,8,9,10,11,12], 1000)

for item in output:
    print(f'Item:{item}')
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
Benutzeravatar
__blackjack__
User
Beiträge: 1460
Registriert: Samstag 2. Juni 2018, 10:21

Sonntag 1. Juli 2018, 20:06

@ThomasL: Ja, ich weiss was ein Generator ist. Natürlich wird nichts durchlaufen wenn man keine Elemente abfragt, aber es werden ja Elemente abgefragt, sonst wäre es sinnlos den Generator zu erstellen.

Wieso ist es Quatsch 1000 Elemente zu übergeben und 1005 zurückbekommen zu wollen? Genau darum geht es doch. Original halt nicht 1000 und 1005 sondern es werden 12 Elemente übergenen und man möchte 1000 haben. Also statt ``my_generator(range(12), 1000)`` im Original war mein Beispiel ``my_generator(range(1000), 1005)``.

Den Code muss ich nicht laufen lassen und auch keine Erklärung finden, denn bei *der* Ausgabe sieht man das Problem nicht, denn die zeigt *nicht* wie oft die ``for``-Schleife durchlaufen wird. Wenn der Code das zeigen würde, dann hättest Du das Problem ja verstanden und würdest nicht mit Worten wie Murks und Quatsch in *meine* Richtung werfen. ;-)

Lass *Du* doch mal *das* hier laufen, wo in jedem Durchlauf der ``for``-Schleife ein Sternchen ausgegeben wird, und erkläre mir warum da 10 statt 6 Sternchen ausgegeben werden. Bei meinem Beispiel wären es dann 2000 statt 1005.

Code: Alles auswählen

def my_generator(my_list, count):
    counter = count + 1
    while counter > 0:
        for item in my_list:
            print('*') # eingefügt
            counter -= 1
            if counter > 0:
                yield item

for item in my_generator(range(5), 6):
    print(item)
Ausgabe:

Code: Alles auswählen

*
0
*
1
*
2
*
3
*
4
*
0
*
*
*
*
Da sind am Ende mindestens drei Sternchen zu viel.

Code: Alles auswählen

    **** COMMODORE 64 BASIC V2 ****
 64K RAM SYSTEM  38911 BASIC BYTES FREE
   CYBERPUNX RETRO REPLAY 64KB - 3.8P
READY.
█
Antworten