• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

python zadanie z użyciem funkcji generatora

Cloud VPS
0 głosów
950 wizyt
pytanie zadane 26 września 2018 w Python przez karo Nowicjusz (120 p.)

Cześć ! Mam do napisania funkcję generatora która przyjmuje takie parametry (sekwencja,*sekwencje). Akceptowane argumenty to dowolne sekwencje . Jeżeli do funkcji przekazano jedynie sekwencję to zwracany generator zawiera elementy tej sekwencji cyklicznie powtórzone nieskończoną ilość razy . Jeżeli sekwencji jest więcej niż jedna to zwracany generator zawiera krotki elementów równolegle pobrane z sekwencji, przy czym każda jest cykliczne powtórzona nieskończenie wiele razy (xyz, ac => (x,a), (y.b),(z,a) ...) Jeżeli którykolwiek z argumentów jest pusty to zwracany generator też jest pusty.

from itertools import permutations, cycle 
def cykliczny(sekwencja,*sekwencje):
    wynik = []
    if sekwencje:
        for s1 in sekwencja:
            for s2 in sekwencje:
                wynik.extend([list(zip(s1,p))for p in permutations(s2)])
            return wynik
        else:
            return ''.join(cycle(sekwencja))

Dopiero od niedawna uczę się python dlatego proszę o wyrozumiałość . :) 

Czy macie jakieś sugestie co mogę poprawić żeby działało poprawnie? 

3 odpowiedzi

+1 głos
odpowiedź 26 września 2018 przez mokrowski Mędrzec (158,840 p.)
edycja 26 września 2018 przez mokrowski

Trochę nie tędy droga. W języku Python można na kilka sposobów napisać generator:

1. Zwracać z funkcji dane z użyciem yield (będzie wtedy działać domknięcie)

2. Użyć postaci generatorowej i otoczyć ją nawiasami zwykłymi (w wyniku powstanie generator)

3. Użyć wersji obiektowej implementacji generatora (trzeba tworzyć wtedy klasę i zaimplementować odpowiednie metody).

W tym zadaniu masz 2 ścieżki wykonania i to zrobione jest dobrze. W jednej zwracasz proste itertools.cycle(sekwencja) a w drugiej, zip(...) na "opakowanych itertools.cycle(...) sekwencjach".

No to błędny jeszcze kod:

#!/usr/bin/env python3

def cykliczny(sekwencja, *sekwencje):
    from itertools import cycle
    if not sekwencje:
        return cycle(sekwencja)
    return zip(cycle(sek) for sek in (sekwencja, *sekwencje))

if __name__ == '__main__':
    # Dwa testy, pierwsze 10 elementów... 
    for k, v in zip(range(10), cykliczny('abcd')):
        print(v)

    for k, v in zip(range(10), cykliczny('abcd', 'gh', 'qwer')):
        print(v)

Pierwsza ścieżka jest już ok. W drugiej niestety zwraca 3 iteratory:

a
b
c
d
a
b
c
d
a
b
(<itertools.cycle object at 0x1095f3798>,)
(<itertools.cycle object at 0x1095f3750>,)
(<itertools.cycle object at 0x1095f37e0>,)

Czyli trzeba przerobić argumenty zip'a tak aby zwracał rozwinięte argumenty. Chodzi o ten kod

cycle(sek) for sek in (sekwencja, *sekwencje)

Wystarczy że opakujesz je nawiasami ( i ) i będzie z tego generator. Ale niestety nie zostanie on rozwinięty dla zip'a. Wystarczy dodać * (gwiazdkę), co spowoduje rozwinięcie argumentów:

zip(*(cycle(sek) for sek in (sekwencja, *sekwencje)))

Sprawdź jak to działa :)

Jak zauważysz w kodzie, zwracasz albo cykl z 1 sekwencji, albo "zzipowane cykle z pierwszej i dalszych sekwencji". Do takich wyrażeń jest w języku użycie "if po" :) 

#!/usr/bin/env python3

def cykliczny(sekwencja, *sekwencje):
    from itertools import cycle
    return cycle(sekwencja) if not sekwencje else zip(*(cycle(sek) for sek in (sekwencja, *sekwencje)))

if __name__ == '__main__':
    # Dwa testy...
    for k, v in zip(range(10), cykliczny('abcd')):
        print(v)

    for k, v in zip(range(10), cykliczny('abcd', 'gh', 'qwer')):
        print(v)

Teraz tylko wystarczy zauważyć że tak naprawdę wystarczy w implementacji jedna ścieżka wykonania. To skończy implementację:

#!/usr/bin/env python3

def cykliczny(*args):
    from itertools import cycle
    return zip(*(cycle(sek) for sek in args))

if __name__ == '__main__':
    # Dwa testy...
    for k, v in zip(range(10), cykliczny('abcd')):
        print(v)
    for k, v in zip(range(10), cykliczny('abcd', 'gh', 'qwer')):
        print(v)

 

komentarz 26 września 2018 przez adrian17 Mentor (354,120 p.)
Zaspoilowałeś rozwiązanie, miałem nadzieję że powoli do tego sam dojdzie. Mógłbyś proszę schować rozwiązania/odpowiedź proszę? :)
0 głosów
odpowiedź 26 września 2018 przez adrian17 Mentor (354,120 p.)

Przede wszystkim, to nie generator. Kluczowym komponentem generatora jest słowo kluczowe 'yield', którego tutaj nie widzę. (zwracania generatora przez `return cycle()` technicznie wygląda jak generator, ale nie jestem przekonany że o to w tym zadaniu chodziło)

return ''.join(cycle(sekwencja))

To jest efektywnie nieskończona pętla - ''.join() nigdy nie wyjdzie. Nie rozumiem, czemu w ogóle tu są operacje na stringach.

else:

to raczej powinno być `else` do `if`a, nie do pętli.

wynik.extend([list(zip(s1,p))for p in permutations(s2)])

Pomijając fakt, że to znowu nie wygląda jak generator, to też nie wygląda jak to, czego wymaga treść zadania. Z czytania treści, nie wydaje mi się by permutations() było potrzebne - jedynie połączenie cycle() i zip().

komentarz 26 września 2018 przez Benek Szeryf (93,190 p.)

Zestawienie for/else występuje w Pythonie.

komentarz 26 września 2018 przez adrian17 Mentor (354,120 p.)
Tak, wiem. Ale patrząc na treść zadania, jestem mocno przekonany że w tym przypadku `else` zostało umieszczone w złym miejscu
komentarz 26 września 2018 przez Benek Szeryf (93,190 p.)

Rzeczywiście, ach te wcięcia wink

komentarz 26 września 2018 przez karo Nowicjusz (120 p.)

Faktycznie , nie zauważyłam wcięcia. wink Poprawiłam tamto i zastąpiłam cycle iteratorem , ale nadal nie działa sad

def cykliczny(sekwencja,*sekwencje):
    wynik = []
    if sekwencje:
        for s1 in sekwencja:
            for s2 in sekwencje:
                wynik.extend([list(zip(s1,s2))])
            yield wynik
    else:
        for element in sekwencja:
            yield element
            saved.append(element)
        while saved:
            for element in saved:
                  yield element

 

komentarz 26 września 2018 przez adrian17 Mentor (354,120 p.)
Druga część (bez dodatkowych sekwencji) wygląda prawie poprawnie (choć przekombinowanie), bo nigdzie nie stworzyłeś `saved`.

W pierwszej części, przede wszystkim, nie widzę nieskończonej iteracji. Poza tym, `yield`ujesz listę list, co też wygląda dziwnie.
0 głosów
odpowiedź 26 września 2018 przez Hunter94 Mądrala (6,290 p.)

Napisałem taki kodzik na szybko, pewnie dałoby się jakoś ładniej / lepiej ale ważne że działa wink
 

def multiple_generator(*args):
    generator_list = []

    def get_next_elem(sequence):
        while True:
            for i in sequence:
                yield i

    if len(args) == 1:
        gen = get_next_elem(*args)
        while True:
            yield next(gen)

    elif len(args) == 0:
        while True:
            yield None

    else:
        for j in args:
            generator_list.append(get_next_elem(j))

        while True:
            yield tuple(next(x) for x in generator_list)

arr = [2, 3, 7, 8]
arr2 = [1, 4, 0, 3]
arr3 = [8, 4, 3, 0]


a = multiple_generator(arr, arr2, arr3)
for i in range(50):
    print(next(a))

 

Podobne pytania

0 głosów
0 odpowiedzi 128 wizyt
pytanie zadane 5 lipca 2020 w Python przez BezBarwny Użytkownik (700 p.)
0 głosów
0 odpowiedzi 160 wizyt
pytanie zadane 20 maja 2021 w Python przez osobliwy nick Użytkownik (900 p.)
0 głosów
0 odpowiedzi 1,220 wizyt
pytanie zadane 2 lipca 2021 w Python przez Nalesniolek Nowicjusz (180 p.)

93,456 zapytań

142,451 odpowiedzi

322,721 komentarzy

62,837 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj

Kursy INF.02 i INF.03
...