Python – A Collatz-szekvencia
On december 1, 2020 by adminKaphatnék egy áttekintést a Collatz-szekvencia kódjáról a fejezetből három a Automatizálja az unalmas dolgokat Python-nal ?
A Collatz-szekvencia
Írjon egy collatz () nevű függvényt, amelynek egy paramétere van, amelynek neve szám. Ha a szám páros, akkor a collatz () kinyomtatja a // 2 számot, és visszaadja ezt az értéket. Ha a szám páratlan, akkor a collatz () kinyomtatja és visszaküldi a 3 * számot + 1.
Ezután írjon egy programot, amely egész számot ír be a felhasználó számára, és amely folyamatosan hívja az adott számra a collatz () parancsot, függvény adja vissza az 1. értéket. (Elképesztő módon ez a szekvencia valójában bármely egész számra érvényes – előbb-utóbb ennek a sorrendnek az alkalmazásával elérheti az 1-et! Még a matematikusok sem tudják, miért. A program azt vizsgálja, hogy mi az úgynevezett Collatz-szekvencia. , néha „a legegyszerűbb lehetetlen matematikai probléma” -nak hívják.)
Ne felejtse el az input () visszatérési értékét egész számra konvertálni az int () függvénnyel; ellenkező esetben karakterlánc lesz.
Tipp: Az egész szám páros, ha a% 2 == 0 szám, és páratlan, ha a (z)% 2 == 1.
Ennek a programnak a kimenete így nézhet ki:
Enter number: 3 10 5 16 8 4 2 1
Bevitel érvényesítése
Adjon hozzá try és kivétel utasításokat az előző projekthez annak megállapításához, hogy a felhasználó beír-e egy nemintegrációs karakterláncot. Normális esetben az int () függvény egy ValueError hibát vet fel, ha egy nemintegrációs karakterláncot adnak át neki, mint az int (“kiskutya”) esetében. A kivétel záradékban nyomtasson ki egy üzenetet a felhasználónak, mondván, hogy egész számot kell megadnia.
Főleg arra vagyok kíváncsi, hogy van-e tisztább módszer a saját megoldás.
def collatz(num): while num > 1: if num % 2 == 0: print(num//2) num = num //2 elif num % 2 ==1: print(3*num+1) num = 3*num+1 else: print(num) def getNum(): global num num = (input("> ")) try: num = int(num) except ValueError: print("plese enter a number") getNum() getNum() collatz(num)
Megjegyzések
- Kérjük, adjon meg néhány leírást arról, hogy mit javasol ez a 3. fejezet, az input és output példákkal, senki ‘ nem fogja kitalálni, mi ez
- @Edmad Broctor és @ Carcigenicate Köszönjük visszajelzését. Folytattam és átdolgoztam a bejegyzésemet.
- ” Elképesztően meglepő, hogy ez a sorrend valójában bármely egész számra érvényes – előbb-utóbb ezt a sorrendet használva megérkezik 1-nél! ” Valójában nem tudjuk, hogy bármelyik egész számra érvényes, az az ötlet, hogy mindig eléri az 1-et, sejtés .
- @PierreCath é Igazán csodálatos módon bemutatom ezt a javaslatot, amelyet ez a megjegyzésdoboz túl kicsi ahhoz, hogy tartalmazzon.
- @Akumuláció Azta ! Ez ‘ lenyűgöző, ebben az esetben frissítse a Wikipedia cikket, és vegye fel a kapcsolatot a Nemzetközi Matematikai Unióval, hogy összegyűjtse a Fields-érmet.
Válasz
Először vegye figyelembe, hogyan másolja a számításokat:
print(num//2) num = num //2
Ez előfordulhat nem okoz problémát ezzel a speciális kóddal, de ez nem jó gyakorlat. Kétszer annyi munkát végez, mint amennyire szüksége van, ami teljesítményproblémákat okozhat, ha bonyolultabb kódot kezd írni. Végezze el egyszer a számítást, és mentse el az eredményt. Ebben az esetben azonban csak annyit kell tennie, hogy megfordítja ezeket a sorokat és használja a következőt: num
:
num = num // 2 print(num)
Ezenkívül ellenőrizze, hogy megfelelő távolság van-e
az operátorok körül, és legyen következetes .
Az Ön if
és elif
az esetek kizárják egymást, és a else
-nek soha nem szabad megtörténnie. Ha az első feltétel igaz, akkor a másiknak hamisnak kell lennie és fordítva. Nincs szükség a második ellenőrzés. Miután átírta, látni fogja, hogy a nyomtatás minden esetben nem szükséges. Csak utána nyomtathat:
while num > 1: if num % 2 == 0: num = num // 2 else: num = 3 * num + 1 print(num)
Mivel Ön csak újra alkalmazza a num
lehetőséget a két lehetőség egyikére feltétel, egy feltételes kifejezés itt is tisztán használható:
while num > 1: num = (num // 2) if num % 2 == 0 else (3 * num + 1) print(num)
A zárójelekre nincs szükség, de szerintem itt hasznosak a az érintett operátorok száma.
A számok nyomtatása itt nem ideális. A legtöbb kódban képesnek kell lennie az előállított adatok felhasználására . Ha elemezni akarná az előállított szekvenciát, akkor valamit tennie kellene az stdout elfogásával, ami drága és túl bonyolult. Legyen függvény, amely felhalmozódik és visszaad egy listát.A következő példákban néhány típusú tippet is felvettem, hogy világosabbá tegyem az adatok típusát:
from typing import List def collatz(starting_num: int) -> List[int]: nums = [starting_num] num = starting_num while num > 1: num = (num // 2) if num % 2 == 0 else (3 * num + 1) nums.append(num) return nums
Vagy sokkal tisztább megközelítés az, ha generátorrá teszik, amely a számokat adja :
# Calling this function returns a generator that produces ints # Ignore the two Nones, as they aren"t needed for this kind of generator def collatz_gen(starting_num: int) -> Generator[int, None, None]: yield starting_num num = starting_num while num > 1: num = (num // 2) if num % 2 == 0 else (3 * num + 1) yield num >>> list(collatz_gen(5)) [5, 16, 8, 4, 2, 1]
Néhány figyelemre méltó dolog getNum
:
A Python a “kígyóház” -ot használja, nem a “camelCase” -et.
A global num
itt felesleges és zavaró. . Csakúgy, mint korábban, kifejezetten return
minden olyan adatot, amelyet a függvény előállít:
def get_num() -> int: raw_num = input("> ") try: return int(raw_num) except ValueError: print("Please enter a number") return get_num()
Ne feledje, hogy a globális num
, csak visszaadjuk a számot. Kicsit elosztottam a dolgokat, és néhány megfelelőbb nevet használtam. Fogalmilag azt mondanám, hogy a num = input("> ")
téves. A futás idején a num
nem számot tartalmazzon (tartalmaz egy karakterláncot).
Ez nem megfelelő a rekurzió használatára. valószínűleg nem okoz problémát, de ha a felhasználó valóban hülye és ~ 1000-szer ad hibás adatokat, akkor a program összeomlik. Csak használjon egy ciklust:
def get_num() -> int: while True: raw_num = input("> ") try: return int(raw_num) except ValueError: print("Please enter a number")
Azokban a nyelvekben, mint a Python, vigyázzon a rekurzió használatára olyan esetekben, amikor nincs garancia arra, hogy a függvény hányszor fog visszatérni.
I “d valószínűleg ezt nevezze el valami közelebb a ask_for_num
-hez. A “get” nem teszi nagyon egyértelművé, honnan származnak az adatok.
Összességében a következőket kapja:
from typing import Generator def collatz_gen(starting_num: int) -> Generator[int, None, None]: yield starting_num num = starting_num while num > 1: num = (num // 2) if num % 2 == 0 else (3 * num + 1) yield num def ask_for_num() -> int: while True: raw_num = input("> ") try: return int(raw_num) except ValueError: print("Please enter a number")
Amit a következőképpen lehet használni:
num = ask_for_num() for n in collatz_gen(num): print(n)
Válasz
Kérés
A legnyilvánvalóbb rossz gyakorlat itt egy globális változó használata. Ahelyett, hogy mellékhatásként beállítaná a num
funkciót, a függvénynek return
eredményt kell adnia.
getNum()
nem olyan jó név a függvénynek. A PEP 8 , a Python hivatalos stílusútmutatója szerint a függvényneveknek lower_case_with_underscores
kell lenniük. Ezenkívül a “get” azt jelenti, hogy a függvény egy olyan adatrészletet kap le, amelyet valahol már tároltak, ami itt nem így van. Végül a “Num” -nak konkrétabbnak kell lennie.
A rekurzió használata nem megfelelő. Ha ciklust szeretne, írjon ciklust.
def ask_integer(): """ Return an integer entered by the user (repeatedly prompting if the input is not a valid integer). """ while True: try: return int(input("> ")) except ValueError: print("Please enter an integer") num = ask_integer()
collatz
függvény
Szigorúan beszélve, nem követte az utasításokat. A megoldás nem hibás vagy rossz – csak nem a collatz
függvényt hajtotta végre a megadott specifikációnak megfelelően, amely szerint egyetlen számot kell kinyomtatnia és visszaadnia.
def collatz(num): """ Given a number, print and return its successor in the Collatz sequence. """ next = num // 2 if num % 2 == 0 else 3 * num + 1 print(next) return next num = ask_integer() while num > 1: num = collatz(num)
Megjegyzések
Válasz
A teljesség kedvéért rekurzív megvalósítás a collatz
(már van elég jó javaslat a num
beviteléhez):
def collatz(num): print(num) if num == 1: return num if num % 2 == 0: return collatz(num // 2) return collatz(3 * num + 1) collatz(3)
Kimenetek
3 10 5 16 8 4 2 1
Megjegyzések
- Nem ‘ t szerintem ez a válasz segíti az OP-t. Noha a rekurzív definíció bizonyosan lehetséges, ez nem felel meg annak a specifikációnak, amelynek megpróbálnak megfelelni. Ez a kód emellett némi redundanciával is rendelkezik: a függvény mindig 1-et ad vissza (amikor egyáltalán visszatér), akkor miért is lenne visszatérési értéke?
- @MeesdeVries
the function always returns 1 (when it returns at all), so why even have a return value
‘ nem biztos, hogy követem. A rekurziónak alaphelyzetben kell lennie. Csak úgy történik, hogy ebben a példában az alapeset az, hanum == 1
. A példa kimenete azt mutatja, hogy a függvény nem mindig 1-et ad vissza. - A függvény más értékeket nyomtat , de csak az 1 értéket adja vissza.
- Nem vagyok biztos benne, hogy mi a véleménye . Eredeti megjegyzésem megjegyezte, hogy nincs szükség arra, hogy az általad írt függvény bármit is visszaadjon, mert a bemenettől függetlenül mindig az 1-es lesz. Ezért a jobb megvalósítással elkerülhető lenne egyáltalán semmilyen érték visszaadása, hogy elkerülhető legyen az értelmes felvetés. Pl. Azt mondanám, hogy a (rekurziós rész) jobb megvalósítása
if num % 2 == 0: collatz(num//2); elif num > 1: collatz(3 * num + 1)
. - Felhívom Önt, hogy próbálja ki a saját maga által kiírt kódot, hogy lássa ezt nem (legalábbis a pozitív egész szám bevitele esetén). Ha ezt tovább szeretné megvitatni, javasoljuk, hogy vigyük el csevegésre.
next = 3 * num + 1 if num % 2 else num // 2
num % 2
hamis-e; ez ‘ nem állítmány. ‘ újra annak ellenőrzése, hogy ‘ egyenlő-e 0-val. Csak úgy történik, hogy ‘ egyenértékűek a Pythonban.next = ...
beárnyékolja a beépítettnext
. Ebben az összefüggésben ‘ valószínűleg nem veszélyes, de jó, ha tisztában van veleif num % 2 else
, egyetértek azzal, hogy itt fontosabb a szándék megmutatása. ésif num % 2 == 0 else
jobban kommunikálja ezt a szándékot. Egyetértek azzal, hogy át kell neveznie anext
változót. ‘ rossz szokás.