Python-コラッツシーケンス
On 12月 1, 2020 by adminコラッツシーケンスのコードのレビューを章から入手できますか Pythonで退屈なものを自動化する ?
コラッツシーケンス
数値という名前のパラメーターが1つあるcollatz()という名前の関数を記述します。数値が偶数の場合、collatz()は数値// 2を出力し、この値を返す必要があります。数値が奇数の場合、collatz()は3 *数値+1を出力して返す必要があります。
次に、ユーザーが整数を入力できるようにし、その数値に対してcollatz()を呼び出し続けるプログラムを作成します。関数は値1を返します(驚くべきことに、このシーケンスは実際には任意の整数で機能します。遅かれ早かれ、このシーケンスを使用すると、1に到達します!数学者でさえ理由がわかりません。プログラムは、コラッツシーケンスと呼ばれるものを探索しています。 、「最も単純な不可能な数学の問題」と呼ばれることもあります。)
int()関数を使用して、input()からの戻り値を整数に変換することを忘れないでください。それ以外の場合は文字列値になります。
ヒント:整数は数値%2 == 0の場合でも偶数であり、数値%2 == 1の場合は奇数です。
このプログラムの出力は次のようになります:
Enter number: 3 10 5 16 8 4 2 1
入力検証
前のプロジェクトにtryステートメントとexceptステートメントを追加して、ユーザーが整数以外の文字列を入力したかどうかを検出します。通常、int( “puppy”)のように、int()関数に整数以外の文字列が渡されると、ValueErrorエラーが発生します。例外句で、整数を入力する必要があることを示すメッセージをユーザーに出力します。
私は主に、よりクリーンな記述方法があるかどうか疑問に思っています。解決策。
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)
コメント
- 入力と出力の例とともに、この第3章で推奨されていることを示す説明を追加してください。'はそれが何であるかを推測しません
- @EdmadBroctorと@Carcigenicateフィードバックをありがとうございます。先に進んで投稿を修正しました。
- "驚くべきことに、このシーケンスは実際にはどの整数でも機能します。遅かれ早かれ、このシーケンスを使用すると、到着します。 at 1!"実際には'どの整数でも機能するかどうかはわかりません。常に1に達するという考えは、推測です。 。
- @PierreCath éこのコメントボックスが小さすぎて含めることができないこの提案の本当に素晴らしいデモンストレーションがあります。
- @Acccumulationうわー !その'は印象的です。その場合は、ウィキペディアの記事を更新し、国際数学連合に連絡してフィールズ賞を集める必要があります。
回答
まず、計算をどのように複製しているかに注意してください:
print(num//2) num = num //2
この特定のコードで問題を引き起こすことはありませんが、それは良い習慣ではありません。必要な作業の2倍の作業を行っているため、より複雑なコードを書き始めるとパフォーマンスの問題が発生する可能性があります。計算を1回実行して結果を保存します。ただし、この場合は、これらの行を逆にするだけです。 num
を使用します:
num = num // 2 print(num)
また、適切な間隔があることを確認してください演算子の周囲で、一貫性を保つ。
if
とelif
ケースは互いに排他的であり、else
が発生することはありません。最初の条件が真の場合、他の条件は偽である必要があり、その逆も同様です。 2回目のチェック。書き直すと、すべての場合に印刷する必要がないことがわかります。次の後に印刷できます:
while num > 1: if num % 2 == 0: num = num // 2 else: num = 3 * num + 1 print(num)
num
を再評価しているので、条件、条件式はここでもきれいに使用できます:
while num > 1: num = (num // 2) if num % 2 == 0 else (3 * num + 1) print(num)
中括弧は必要ありませんが、中括弧はここでは便利だと思います。関係する演算子の数。
ここで数字を印刷することは理想的ではありません。ほとんどのコードでは、生成したデータを使用できる必要があります。生成されたシーケンスを分析したい場合は、stdoutをインターセプトする何かを行う必要がありますが、これは高価で非常に複雑です。リストを蓄積して返す関数にします。次の例では、データのタイプを明確にするために、タイプのヒントもいくつか追加しました。
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
または、はるかにクリーンなアプローチは、数値を生成するジェネレーターにすることです:
# 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]
getNum
についていくつかの注目すべき点があります:
Pythonは「camelCase」ではなく「snake_case」を使用します。
ここでのglobal num
の使用は不要であり、混乱を招きます。 。前と同じように、関数が生成するデータを明示的にreturn
します。
def get_num() -> int: raw_num = input("> ") try: return int(raw_num) except ValueError: print("Please enter a number") return get_num()
再割り当てする代わりに、グローバルnum
、数値を返すだけです。また、少し間隔を空けて、より適切な名前をいくつか使用しました。概念的には、num = input("> ")
は間違っていると思います。実行時に、num
は しません。数値を含みます(文字列を含みます)。
これは再帰の適切な使用法ではありません。 おそらく問題は発生しませんが、ユーザーが本当に馬鹿で、間違ったデータを1000回まで入力すると、プログラムがクラッシュします。ループを使用するだけです。
def get_num() -> int: while True: raw_num = input("> ") try: return int(raw_num) except ValueError: print("Please enter a number")
Pythonのような言語では、関数が何回再帰するかについて保証がない場合は、再帰の使用に注意してください。
I “dおそらくこれをask_for_num
に近い名前にします。 「get」では、データの出所が明確になりません。
まとめると、次のようになります。
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")
次のように使用できます:
num = ask_for_num() for n in collatz_gen(num): print(n)
回答
プロンプト
ここで最も明らかな悪い習慣は、グローバル変数の使用です。 num
を副作用として設定する代わりに、関数は結果をreturn
する必要があります。
getNum()
はこの関数の名前としてはあまり適切ではありません。 Pythonの公式スタイルガイドである PEP 8 には、関数名はlower_case_with_underscores
である必要があると記載されています。さらに、「get」は、関数がすでにどこかに格納されているデータを取得していることを意味しますが、ここではそうではありません。最後に、「Num」はより具体的にする必要があります。
再帰の使用は適切ではありません。ループが必要な場合は、ループを記述します。
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
関数
厳密に言ってみれば、あなたは指示に従わなかった。あなたの解決策は間違っていたり悪いことではない。与えられた仕様に従ってcollatz
関数を実装しなかっただけだ。 1つの数値を印刷して返す必要があります。
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)
コメント
- おそらくテストを逆にして、削除します。 0との比較:
next = 3 * num + 1 if num % 2 else num // 2
- @RootTwo正直なところ、それが意図を覆していることがわかりました。' re
num % 2
が偽であるかどうかをチェックしていません。'は述語ではありません。' re 'が0に等しいかどうかを確認します。たまたま'はPythonで同等です。 -
next = ...
は組み込みのnext
。このコンテキストでは、'はおそらく危険ではありませんが、注意しておくとよいでしょう - 技術的には、
if num % 2 else
、ここで意図を示すことがより重要であることに同意します。if num % 2 == 0 else
はその意図をよりよく伝えます。ただし、next
変数の名前を変更する必要があることに同意します。 'は悪い習慣です。 - @ 200_success単に印刷するのではなく、番号を返さなかったことを指摘していただきありがとうございます。これは非常に役に立ちました。
回答
完全を期すために、(num
を入力するための十分な提案がすでにあります):
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)
出力
3 10 5 16 8 4 2 1
コメント
- 私は' tこの答えはOPに役立つと思います。再帰的定義は確かに可能ですが、'彼らが満たそうとしている仕様に適合していません。さらに、このコードにはある程度の冗長性があります。関数は常に1を返します(戻り値がある場合)。なぜ戻り値があるのでしょうか?
- @MeesdeVries
the function always returns 1 (when it returns at all), so why even have a return value
'フォローしているかどうかわかりません。再帰にはベースケースが必要です。この例の基本ケースは、num == 1
の場合です。出力例は、関数が常に1を返すとはしないことを示しています。 - 関数は他の値を出力しますが、は値1のみを返します。
- あなたのポイントがわかりません。 。 私の元のコメントは、入力に関係なく常に1になるため、作成した関数が何かを返す必要はないと述べました。 したがって、より良い実装では、意味があるという提案を避けるために、値を返すことをまったく避けます。 たとえば、(再帰部分の)より良い実装は
if num % 2 == 0: collatz(num//2); elif num > 1: collatz(3 * num + 1)
だと思います。 - 自分で書いたコードを試してみて、それを確認してください。 そうではありません(少なくとも、正の整数入力の場合)。 これについてさらに話し合いたい場合は、チャットに参加することをお勧めします。
コメントを残す