Python – Collatz-jakso
On joulukuu 1, 2020 by adminVoinko saada tarkistuksen koodistani Collatz-jaksoon luvusta kolme Automatisoi tylsää sisältöä Pythonilla ?
Collatz-jakso
Kirjoita funktio nimeltä collatz (), jolla on yksi parametri nimeltä numero. Jos numero on parillinen, collatz () tulosta numero // 2 ja palauttaa tämän arvon. Jos numero on pariton, collatz (): n tulisi tulostaa ja palauttaa 3 * numero + 1.
Kirjoita sitten ohjelma, joka antaa käyttäjän kirjoittaa kokonaisluvun ja kutsuu Collatz (): a numeroon, kunnes funktio palauttaa arvon 1. (Hämmästyttävää kyllä, tämä sekvenssi toimii mihin tahansa kokonaislukuun – ennemmin tai myöhemmin, käyttämällä tätä sekvenssiä, tulet arvoon 1! Jopa matemaatikot eivät ole varmoja miksi. Ohjelmasi tutkii Collatz-sekvenssin , jota joskus kutsutaan ”yksinkertaisimmaksi mahdottomaksi matemaattiseksi tehtäväksi”.)
Muista muuntaa palautusarvo syötteestä () kokonaislukuksi funktiolla int (); muuten se on merkkijonoarvo.
Vihje: Kokonaisluvun luku on tasainen, vaikka luku% 2 == 0, ja se on outo, jos luku% 2 == 1.
Tämän ohjelman tulos voi näyttää tältä:
Enter number: 3 10 5 16 8 4 2 1
Syötteen vahvistus
Lisää kokeilu- ja poikkeuslausekkeet edelliseen projektiin selvittääksesi, kirjoittaako käyttäjä eiinteger-merkkijonon. Normaalisti int () -funktio herättää ValueError-virheen, jos se välitetään ei-integraalimerkkijono, kuten int (”pentu”). Tulosta paitsi lauseessa käyttäjälle viesti, jonka mukaan heidän on syötettävä kokonaisluku.
Mietin lähinnä, onko olemassa puhtaampaa tapaa kirjoittaa oma ratkaisu.
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)
Kommentit
- Lisää kuvaus, josta käy ilmi tämän luvun 3 asia, ja esimerkkejä syötteistä ja lähdöistä. Kukaan ’ ei aio arvata mikä se on
- @Edmad Broctor ja @ Carcigenicate Kiitos palautteestasi. Menin eteenpäin ja tarkistin viestiäni.
- ” Hämmästyttävää kyllä, tämä sekvenssi toimii mihin tahansa kokonaislukuun – ennemmin tai myöhemmin, käyttämällä tätä järjestystä, tulet at 1! ” Itse asiassa emme tiedä, että se toimii mille tahansa kokonaisluvulle, ajatus, että se saavuttaa aina 1, on oletus. .
- @PierreCath é Minulla on todella upea osoitus tästä ehdotuksesta, jota tämä kommenttiruutu on liian pieni sisältämään.
- @Akumulaatio Vau ! Se on ’ vaikuttava, siinä tapauksessa päivitä Wikipedia-artikkeli ja ota yhteys Kansainväliseen matemaattiseen liittoon kerätäksesi Fields-mitali.
Vastaa
Huomaa ensin, kuinka kopioit laskutoimituksia:
print(num//2) num = num //2
Tämä voi ei aiheuta ongelmia tämän erityisen koodin kanssa, mutta se ei ole hyvä käytäntö. Teet kaksi kertaa niin paljon työtä kuin tarvitset, mikä voi aiheuttaa suorituskykyongelmia, kun aloitat monimutkaisemman koodin kirjoittamisen. Tee laskenta kerran ja tallenna tulos. Tässä tapauksessa sinun tarvitsee kuitenkin vain kääntää nämä rivit ja käytä num
:
num = num // 2 print(num)
Varmista myös, että sinulla on oikea väli operaattoreiden ympärillä ja ole johdonmukainen .
if
ja elif
tapaukset eivät koske toisiaan, ja else
-asi ei pitäisi koskaan tapahtua. Jos ensimmäinen ehto on totta, muiden on oltava väärät ja päinvastoin. Ei tarvita toinen tarkistus. Kun olet kirjoittanut uudestaan, huomaat, että tulostaminen ei ole tarpeen. Voit tulostaa vain sen jälkeen:
while num > 1: if num % 2 == 0: num = num // 2 else: num = 3 * num + 1 print(num)
Koska olet vain käyttämässäsi num
yhtä kahdesta vaihtoehdosta condition, ehdollista lauseketta voidaan käyttää myös tässä puhtaasti:
while num > 1: num = (num // 2) if num % 2 == 0 else (3 * num + 1) print(num)
Aaltosulkeita ei tarvita, mutta mielestäni ne ovat tässä hyödyllisiä johtuen mukana olevien operaattoreiden määrä.
Numeroiden tulostaminen ei ole ihanteellinen tässä. Useimmissa koodeissa sinun on pystyttävä käyttämään tuottamiasi tietoja. Jos haluat analysoida tuotettua sekvenssiä, joudut tekemään jotain pysäyttämään stdout, joka on kallista ja liian monimutkaista. Tee siitä funktio, joka kerää ja palauttaa luettelon.Seuraaviin esimerkkeihin lisäin myös joitain -tyyppivinkkejä , jotta tietojen tyyppi olisi selkeämpi:
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
Tai paljon puhtaampi lähestymistapa on tehdä siitä generaattori, joka tuottaa numerot :
# 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]
Siellä on muutama merkittävä asia getNum
:
Python käyttää ”snake_case” , ei ”camelCase”.
global num
: n käyttö tässä on tarpeetonta ja hämmentävää . Aivan kuten aikaisemmin, return
kaikki toiminnon tuottamat tiedot:
def get_num() -> int: raw_num = input("> ") try: return int(raw_num) except ValueError: print("Please enter a number") return get_num()
Huomaa, miten määrität global num
, palautamme vain numeron. Sijoitin myös asioita hieman ja käytin sopivampia nimiä. Käsitteellisesti sanoisin, että num = input("> ")
on väärä. Juoksuhetkellä num
ei sisältää numeron (se sisältää merkkijonon).
Tämä ei ole hyvä rekursio. Se todennäköisesti ei aiheuta sinulle mitään ongelmia, mutta jos käyttäjäsi on todella tyhmä ja syöttää vääriä tietoja ~ 1000 kertaa, ohjelma kaatuu. Käytä vain silmukkaa:
def get_num() -> int: while True: raw_num = input("> ") try: return int(raw_num) except ValueError: print("Please enter a number")
Pythonin kaltaisissa kielissä ole varovainen rekursiota käytettäessä, jos sinulla ei ole takeita siitä, kuinka monta kertaa toiminto toistuu.
I ”d nimeä tämä todennäköisesti lähemmäksi ask_for_num
. ”get” ei tee siitä selvää, mistä tiedot ovat peräisin.
Kaiken kaikkiaan päädyt:
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")
joita voidaan käyttää kuten:
num = ask_for_num() for n in collatz_gen(num): print(n)
vastaus
Kehote
Tässä ilmeisin huono käytäntö on globaalin muuttujan käyttö. Sen sijaan, että asetat num
sivuvaikutukseksi, toiminnon tulisi olla return
tulos.
getNum()
ei ole niin hyvä nimi toiminnolle. Pythonin virallinen tyyliopas PEP 8 sanoo, että funktioiden nimien tulisi olla lower_case_with_underscores
. Lisäksi ”get” tarkoittaa, että toiminto hakee tietoihin pala, joka on jo tallennettu jonnekin, mitä ei ole tässä tapauksessa. Lopuksi ”Num”: n tulisi olla tarkempi.
Rekursiota ei ole tarkoituksenmukaista käyttää. Jos haluat silmukan, kirjoita silmukka.
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
-toiminto
Tiukasti Puhuessasi et noudattanut ohjeita. Ratkaisusi ei ole väärä tai huono – et vain toteuttanut funktiota collatz
annettujen spesifikaatioiden mukaisesti. tulosta ja palauta yksi yksittäinen numero.
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)
Kommentit
Vastaus
Täydellisyyden vuoksi rekursiivinen toteutus kohteelle collatz
(sinulla on jo tarpeeksi hyviä ehdotuksia num
syöttämiseen):
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)
Lähdöt
3 10 5 16 8 4 2 1
Kommentit
- En halua ’ luulen, että tämä vastaus auttaa OP: ta. Vaikka rekursiivinen määritelmä on varmasti mahdollinen, se ei ’ ei sovi määritykseen, jota he yrittävät täyttää. Lisäksi tällä koodilla on jonkin verran redundanssia: funktio palauttaa aina 1 (kun se palaa ollenkaan), joten miksi edes paluuarvo?
- @MeesdeVries
the function always returns 1 (when it returns at all), so why even have a return value
En ’ ole varma, että noudatan. Rekursiolla on oltava perustapaus. Sattuu, että tämän esimerkin perustapaus on, josnum == 1
. Esimerkkilähtö osoittaa, että funktio ei aina palauta arvoa 1. - Funktio tulostaa muita arvoja, mutta se palauttaa vain arvon 1.
- En ole varma, mitä mieltä olet . Alkuperäinen kommenttini huomautti, että kirjoittamasi funktion ei tarvitse palauttaa mitään, koska se on aina numero 1 syötteestä riippumatta. Siksi parempi toteutus välttäisi arvon palauttamisen lainkaan, jotta vältettäisiin ehdotus sen merkityksellisyydestä. Esimerkiksi, sanoisin, että (rekursio-osan) parempi toteutus on
if num % 2 == 0: collatz(num//2); elif num > 1: collatz(3 * num + 1)
. - Kutsun sinut kokeilemaan itse kirjoittamaani koodia nähdäksesi sen se ei (ainakaan positiivisen kokonaisluvun syötteelle). Jos haluat keskustella asiasta edelleen, suosittelen, että vietämme sen keskusteluun.
next = 3 * num + 1 if num % 2 else num // 2
num % 2
väärä; se ’ ei ole predikaatti. Me ’ uudelleen tarkistetaan, onko se ’ yhtä suuri kuin 0. Tapahtuu, että ne ’ vastaavat Pythonissa.next = ...
varjostaa sisäänrakennetunnext
. Tässä yhteydessä se ’ ei todennäköisesti ole vaarallista, mutta hyvä tietää siitä.if num % 2 else
, olen samaa mieltä siitä, että aikomuksen osoittaminen tässä on tärkeämpää. jaif num % 2 == 0 else
kommunikoi tuon tarkoituksen paremmin. Hyväksyn, että sinun pitäisi kuitenkin nimetä muuttujanext
. Se ’ on huono tapa.