• 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

Object Storage Arubacloud
0 głosów
647 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 (155,460 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 Ekspert (344,840 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 Ekspert (344,840 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 (90,790 p.)

Zestawienie for/else występuje w Pythonie.

komentarz 26 września 2018 przez adrian17 Ekspert (344,840 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 (90,790 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 Ekspert (344,840 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 103 wizyt
pytanie zadane 5 lipca 2020 w Python przez BezBarwny Użytkownik (700 p.)
0 głosów
0 odpowiedzi 110 wizyt
pytanie zadane 20 maja 2021 w Python przez osobliwy nick Użytkownik (900 p.)
0 głosów
0 odpowiedzi 874 wizyt
pytanie zadane 2 lipca 2021 w Python przez Nalesniolek Nowicjusz (180 p.)

92,535 zapytań

141,376 odpowiedzi

319,449 komentarzy

61,920 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.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...