ちょっとしたPythonプログラム01-公約数(約数)を見つける

公開:2020/09/20
更新:2020/09/20
8 min読了の目安(約4900字TECH技術記事

タイトルの通り、公約数(約数)を見つけるプログラムを書いてみました。

1.はじめに

  • 初学者レベルが書いたものです。
  • 同じ初学者の方々にも簡単に理解できるような解説を目指しています。(そのため中級者レベル以上の方には長すぎるかもしれません)
  • ベターなものではないと思います。コードレビューもお待ちしています。
  • 初投稿です。読みにくい記事であればごめんなさい。宜しければアドバイス (おすすめの文章の書き方など) 等お願いします。
  • 質問もお気軽にどうぞ~、出来る範囲でお答えします。

2.今回のコード

def numbers_input():
    nums = []
    print("数値を入力して下さい、終了する場合はe")
    while True:
        num = input()
        if num == "e":
            print("入力終了")
            break
        try:
            num = int(num)
        except ValueError:
            print("数値またはeでは無いようです。")
            continue
        if num <= 0:
            print("0または負の数は使用できません。")
            continue
        nums.append(num)
    if len(nums) == 0:
        print("何も数値を入力していません。終了します。")
        return None
    return nums


def divisor(*nums):
    nums = list(set(nums))
    current_number = 2
    exec_type = "約数" if len(nums) == 1 else "公約数"
    divisors = []
    while current_number <= min(nums):
        divided_numbers = [num % current_number for num in nums]
        if divided_numbers[0] == 0 and len(set(divided_numbers)) == 1:
            divisors.append(current_number)
        current_number += 1
    if exec_type == "約数":
        divisors.remove(nums[0])
    if not divisors:
        content = "これは素数です" if exec_type == "約数" else "1以外の公約数が見つかりませんでした"
        print(content)
    else:
        print(f"1以外の{exec_type}が見つかりました:" + ",".join(map(str, divisors)))


if __name__ == "__main__":
    nums = numbers_input()
    if nums:
        divisor(*nums)

今回書いたコードです。

3.解説

↑のコードを読んで理解できた方は読み飛ばして下さい。

if __name__ == "__main__"

実行部分です。
詳しくはこちら→ Pythonの if __name__ == '__main__' の使い方【初心者向け】 | TechAcademyマガジン

numbers_input関数

Pythonの標準関数input() (値を受け取る関数) を繰り返し実行し、複数の値を受け取って返します。

"e"と入力するとその時点で入力を終了します。また、数値ではないものや0、負の数については受け取りません。

何も受け取らないとNoneを返します。(何も数がないのに以下の関数を実行することを防ぐことが可能)

divisor関数

引数に1つ以上の数値を受け取り、公約数(引数が1つの場合は約数)をprintします。今回メインの関数です。

変数定義

変数名 説明
nums 受け取った引数の重複を削除しリスト化しています。
exec_type 公約数かただの約数かをnums変数内の要素数で決定しています。
divisors 公約数または約数を保存しておくリストです。
current_number 割り切ろうとする数値です。1がすべての数の約数であることは自明なので2で初期化しています。(詳しくは後述)

while current_number <= min(nums)

公約数または約数か判定する処理を行っています。

while 条件式のかたちでループ処理を行っています。条件式が偽になるまでループが継続します。

公約数というのは例えば「10,20,100」という数値を与えたとき、「1,2,5,10」です。

この場合与えた数の最小値は「10」で、公約数がそれを超えることは絶対にありませんよね。(約数の場合もその数自身を超えることはない)

そのため、current_numberが与えた引数の中で最小の値を超えたらループを終了させています。

current_number変数について

この変数は、「現在割り切ろうとしている数」を表します。

割り切ろうとするごとに1つずつ加算されていきます。

例えば「10,100」という数値が与えられた時、

2で割り切ろうとする→3で割り切ろうとする→4で割り切ろうとする→...(10まで続く)
という感じです。

変数名 説明
divided_numbers 内包表記を使っています。与えられた数値をすべてcurrent_numberで割ってその余りをリスト化しています。
if divided_numbers[0] == 0 and len(set(divided_numbers)) == 1:
    divisors.append(current_number)

は、

divided_numbers[0] == 0divided_numbersの1つ目の要素 (=余り) が0であることを。

len(set(divided_numbers))divided_numberリストの重複がない=すべての余りが同じであること。

それぞれ判定していて、2つをandでつなぐことで、「すべての余りが0である」ことを判定しています。

すべての余りが0である場合、divisors.append(current_number)divisorsリストに現在のcurrent_number=公約数または約数 を追加しています。

current_number += 1current_numberに1加算してループします。(前述したとおり与えた引数の中で最小の値を超えたら終了します)

if exec_type == "約数"

約数を判定している場合 (公約数ではない) 、divisors.remove(nums[0])で「その数自身を除外」しています。(自明なため)

if not divisorselse

公約数または約数が見つからなかったとき、公約数を判定していたときは「1以外の公約数が見つかりませんでした」、約数を判定していたときは「これは素数です」とprintしています。

見つかったときはprint(f"1以外の{exec_type}が見つかりました:" + ",".join(map(str, divisors)))で一覧をprintしています。

{exec_type}は「約数」か「公約数」のどちらかですね。f-stringsと呼ばれるもので直接文字列の中に埋め込んでいます。

",".join(map(str, divisors))はdivisorsリストの中身を文字列型にしてからカンマで区切っています。

これで処理終了となります。

4.今回使ったものまとめ

一つ一つ説明を書いているとものすごく大変なので箇条書きにします。

関数

  • print
  • int
  • input
  • set
  • list
  • len

  • for
  • while
    • break
    • continue
  • try
    • except
  • if
    • else
  • return

メソッド

  • append
  • remove

5.終わりに

Memo

  • 数値はisdecimalを使うといいらしい
  • exec_type読みにくいのでどうにかしたい

今回はメインではないので省きましたが、numbers_inputについてはもうちょっと詳しく解説書こうかと思います。

限りなく丁寧な解説を目指しましたが、読みにくければ 1.はじめに にも書いたとおりアドバイス等して頂ければ幸いです。

この「ちょっとしたPythonプログラム」は自分と同じ初学者向けのシリーズとしたいと思います。

目標は「今日からPython始めるよ!」という人でも簡単に理解できてステップアップ出来るような記事にすることです。

それでは良いPythonライフを!