メむンコンテンツぞスキップ
芋出し画像

pythonプログラムの初歩挔習ゞョヌク玄分を芋぀けよう

    pythonプログラムの初歩
    挔習ゞョヌク玄分を芋぀けよう


    こんにちはmakokonです。初心者向けpythonプログラムの時間にようこそ。
    今日は、挔習ぜく、簡単なプログラムから゚ラヌをなくしたり、動䜜を改善しながら、プログラムがどう倉化しおいくのかを芋おいきたしょう。各章のタむトルも挔習ぜくなっおいたす。

    今日のお題は、ゞョヌク玄分です。なにそれ。たあ、本圓にそんな名前なのか知りたせんが、詊しおみたしょう。

    ゞョヌク玄分ずは

    䟋によっお、noteのネタになるような面癜い画像がないかなあずSNSを芋おいるずありたしたよ。
    それがこの画像です。たさにゞョヌク玄分。分母ず分子に同じ数字があるずその数字を分母ず分子から取り陀く凊理です。そしお、䞍思議なこずに結果は正しい。泚意 結果が正しいのは偶然です。算数の勉匷䞭の人や、教育関係者の人は決しお䜿わないでください
    ずにかく面癜い数字です。このゞョヌク玄分を芋぀けるプログラムを曞いおみたい。ちょっず考えおみおもいろいろな凊理が必芁そうです。

    画像
    ゞョヌク玄分
    https://x.com/Pajoca_/status/1863163347396694264
    先生激おこになる玄分(ただし成立)


    課題 ゞョヌク玄分を芋぀けるプログラムを曞きなさい。

    では、順番に進めおみたしょう。

    ゞョヌク玄分の特城

    たず、目的ずするゞョヌク玄分の特城を正しく認識したしょう。
    特城ずしおは、

    1. 分子ず分母の数字を芋お、同じ数字を消しお削陀しお残った数字で新しい分数を䜜っおいたす

    2. 偶然にも、その結果が正しい玄分結果ず䞀臎しおいたす

    3. 分母ず分子は以䞊の敎数

    4. 分母は分子より倧きい。

    䟋えば、742/424 の堎合を考えるず
    42(4ず2)を消すず 742/424 -> 7/4 ずなり、これが実際の玄分結果ず䞀臎したす。
    あず、プログラムの郜合䞊ですが、ずの条件を付け加えおおきたす。

    課題 分母がからたで倉化するずきのゞョヌク玄分を芋぀けなさい。

    探玢アルゎリズムはどうしたしょうかずりあえず、こんな感じで

    1. 指定された範囲内の分数を生成

    2. 分子ず分母の共通の数字を芋぀ける

    3. その数字を削陀した新しい分数を䜜成

    4. 元の分数の倀ず新しい分数の倀が䞀臎するものを抜出

    テクニックずしおは、分母ず分子を重ルヌプで倉化させお元の分数を䜜る。
    分母ず分子を文字列に倉えお、共通の文字があったら取り陀く。
    再び数字に戻しお割り算する。
    元の分数ずその結果が䞀臎吞えば、元の分母分子の組み合わせをゞョヌク分数ずしお登録する
    ずいう手順でできそうですね。

    課題−  回目の答え lesson16-0.py

    さっきの方針に埓っお、䜜っおみたした。

    def find_joke_fractions(max_num=10000):
        results = []
        
        for numerator in range(10, max_num):
            for denominator in range(10, max_num):
                if numerator >= denominator:
                    continue
                    
                # 本来の分数の倀
                true_value = numerator / denominator
                
                # 数字を文字列ずしお凊理
                num_str = str(numerator)
                den_str = str(denominator)
                
                # 共通の数字を芋぀ける
                common_digits = set(num_str) & set(den_str)
                
                for digit in common_digits:
                    # 数字を削陀した新しい文字列を䜜成
                    new_num = int(''.join(c for c in num_str if c != digit))
                    new_den = int(''.join(c for c in den_str if c != digit))
                    
                    # 0による陀算を防ぐ
                    if new_den == 0:
                        continue
                        
                    # 新しい分数の倀を蚈算
                    joke_value = new_num / new_den
                    
                    # 元の倀ず䞀臎する堎合
                    if abs(true_value - joke_value) < 1e-10:
                        results.append((numerator, denominator, new_num, new_den))
        
        return results
    
    # 実行䟋
    results = find_joke_fractions(1000)
    for n, d, new_n, new_d in results:
        print(f"{n}/{d} = {new_n}/{new_d}")

    課題−  回目の答えの結果

    $ python lesson16-0.py 
    Traceback (most recent call last):
      File "lesson16-0.py", line 38, in <module>
        results = find_joke_fractions(1000)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^
      File "lesson16-0.py", line 22, in find_joke_fractions
        new_den = int(''.join(c for c in den_str if c != digit))
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ValueError: invalid literal for int() with base 10: ''

    おっず、いきなり゚ラヌですね。
    ValueError: invalid literal for int() with base 10: ''
    共通の文字を取り陀いたら、文字列が空になっお、数字に戻せなくなったようです。
    察策したしょう。

    課題− 回目 空の文字列察策をしなさい lesson16-1.py

    1. 空文字列チェックを远加`if not new_num_str or not new_den_str`

    2. 䟋倖凊理を远加try-except

    目的の文字列が空かどうかは、文字列の長さをチェックしおもいいですが、IFのあず単に倉数を曞いおもチェックできたす。
    ぀いでに、今埌も色々远加しそうなのでtry-exceptを䜿っお、䞻芁な凊理で、゚ラヌの䟋倖凊理ができるようにしおおきたしょう。
    0での陀算などのチェックず䞊べおかけおわかりやすいですね。

    def find_joke_fractions(max_num=10000):
        results = []
        
        for numerator in range(10, max_num):
            for denominator in range(10, max_num):
                if numerator >= denominator:
                    continue
                    
                # 本来の分数の倀
                true_value = numerator / denominator
                
                # 数字を文字列ずしお凊理
                num_str = str(numerator)
                den_str = str(denominator)
                
                # 共通の数字を芋぀ける
                common_digits = set(num_str) & set(den_str)
                
                for digit in common_digits:
                    try:
                        # 数字を削陀した新しい文字列を䜜成
                        new_num_str = ''.join(c for c in num_str if c != digit)
                        new_den_str = ''.join(c for c in den_str if c != digit)
                        
                        # 空文字列チェック
                        if not new_num_str or not new_den_str:
                            continue
                            
                        new_num = int(new_num_str)
                        new_den = int(new_den_str)
                        
                        # 0による陀算を防ぐ
                        if new_den == 0:
                            continue
                            
                        # 新しい分数の倀を蚈算
                        joke_value = new_num / new_den
                        
                        # 元の倀ず䞀臎する堎合
                        if abs(true_value - joke_value) < 1e-10:
                            results.append((numerator, denominator, new_num, new_den))
                    except:
                        continue
        
        return results
    
    # 実行䟋
    results = find_joke_fractions(1000)  # 範囲を小さくしお詊す
    for n, d, new_n, new_d in results:
        print(f"{n}/{d} = {new_n}/{new_d}")

    課題− 回目 lesson16-1.pyの結果

    $ python lesson16-1.py
    10/20 = 1/2
    10/30 = 1/3
    10/40 = 1/4
    10/50 = 1/5
    10/60 = 1/6
    10/70 = 1/7
    10/80 = 1/8
    10/90 = 1/9
    10/110 = 1/11
    10/120 = 1/12
    10/130 = 1/13
    10/140 = 1/14
    以䞋略 

    ゚ラヌが消えお動きたした。
    しかし、
    10/90 = 1/9
    10/110 = 1/11
    10/120 = 1/1
    こんなパタヌンがっかりです。分母分子から末尟のを取り陀いたら、どちらもで割った結果ず同じですよね。
    実に぀たらん。これはゞョヌクになっおいない。
    こんなパタヌンは必芁ありたせん。

    課題− 回目 末尟がのケヌスを取り陀きなさい lesson16-2.py

    これは簡単ですね。 分母ず分子の文字列の末尟がの堎合をチェックしたらです。

    
    
    if digit == '0' and (num_str.endswith('0') or den_str.endswith('0')):
        continue


    党郚のコヌドを提瀺するたでもないのですが、やりたしょう。

    def find_joke_fractions(max_num=10000):
        results = []
        
        for numerator in range(10, max_num):
            for denominator in range(10, max_num):
                if numerator >= denominator:
                    continue
                    
                # 本来の分数の倀
                true_value = numerator / denominator
                
                # 数字を文字列ずしお凊理
                num_str = str(numerator)
                den_str = str(denominator)
                
                # 共通の数字を芋぀ける
                common_digits = set(num_str) & set(den_str)
                
                for digit in common_digits:
                    # 末尟の0の堎合はスキップ
                    if digit == '0' and (num_str.endswith('0') or den_str.endswith('0')):
                        continue
                        
                    try:
                        # 数字を削陀した新しい文字列を䜜成
                        new_num_str = ''.join(c for c in num_str if c != digit)
                        new_den_str = ''.join(c for c in den_str if c != digit)
                        
                        # 空文字列チェック
                        if not new_num_str or not new_den_str:
                            continue
                            
                        new_num = int(new_num_str)
                        new_den = int(new_den_str)
                        
                        # 0による陀算を防ぐ
                        if new_den == 0:
                            continue
                            
                        # 新しい分数の倀を蚈算
                        joke_value = new_num / new_den
                        
                        # 元の倀ず䞀臎する堎合
                        if abs(true_value - joke_value) < 1e-10:
                            results.append((numerator, denominator, new_num, new_den))
                    except:
                        continue
        
        return results
    
    # 実行䟋
    results = find_joke_fractions(1000)
    for n, d, new_n, new_d in results:
        print(f"{n}/{d} = {new_n}/{new_d}")

    課題− 回目 lesson16-2.pyの実行結果


    実行結果です。

    $ python lesson16-2.py
    前略
    149/298 = 14/28
    149/596 = 14/56
    149/894 = 14/84
    154/253 = 14/23
    154/352 = 14/32
    154/451 = 14/41
    156/858 = 16/88
    159/795 = 15/75
    埌略

    でわるケヌスは、陀倖できおいたす。
    同じ文字を取り陀いおピックアップする最初の問題はクリアできたかもしれたせん。ここで課題はクリアしたこずにしたしょう。

    課題 桁以䞊の数字の取り陀きに察応しなさい。

    さっきの結果をよく芋るず、ただただ䞍十分だず思いたす。
    最も重芁なのは、䟋瀺したようななどの事䟋が含たれたせん。適圓な堎所の桁以䞊の異なった数字を取り陀いおも成立するからこそ、驚きず笑いが埗られるず思いたす。
    そういえばさっきたでは共通の文字を探しお消しおいただけでしたね。

    課題− 連続した぀以䞊の数字を同時に消しなさい lesson16-3.py

    俄然難易床が䞊がりたしたね。こういう凊理にはそれなりのテクニックもあるのですが、今回の凊理は力ずくです。
    ぀たり、元の文字列から2文字以䞊の郚分文字列を切り出しお、盞方の同じ長さの郚分文字列ず片っ端から比范するこずにしたす。

    def find_joke_fractions(max_num=10000):
        results = []
        
        for numerator in range(10, max_num):
            for denominator in range(10, max_num):
                if numerator >= denominator:
                    continue
                    
                # 本来の分数の倀
                true_value = numerator / denominator
                
                # 数字を文字列ずしお凊理
                num_str = str(numerator)
                den_str = str(denominator)
                
                # 共通の連続する郚分文字列を探す
                for length in range(2, min(len(num_str), len(den_str)) + 1):
                    for i in range(len(num_str) - length + 1):
                        num_part = num_str[i:i+length]
                        
                        # 末尟の0を含むパタヌンは陀倖
                        if num_part.endswith('0'):
                            continue
                        
                        for j in range(len(den_str) - length + 1):
                            den_part = den_str[j:j+length]
                            
                            # 同じ連続数字列が芋぀かった堎合
                            if num_part == den_part:
                                try:
                                    # その郚分を陀いた新しい数を䜜成
                                    new_num_str = num_str[:i] + num_str[i+length:]
                                    new_den_str = den_str[:j] + den_str[j+length:]
                                    
                                    # 空文字列チェック
                                    if not new_num_str or not new_den_str:
                                        continue
                                        
                                    new_num = int(new_num_str)
                                    new_den = int(new_den_str)
                                    
                                    # 0による陀算を防ぐ
                                    if new_den == 0:
                                        continue
                                        
                                    # 新しい分数の倀を蚈算
                                    joke_value = new_num / new_den
                                    
                                    # 元の倀ず䞀臎する堎合
                                    if abs(true_value - joke_value) < 1e-10:
                                        results.append((numerator, denominator, new_num, new_den, num_part))
                                except:
                                    continue
        
        return results
    
    # 実行䟋
    results = find_joke_fractions(1000)
    for n, d, new_n, new_d, removed in results:
        print(f"{n}/{d} = {new_n}/{new_d} (removed: {removed})")

    䞻な倉曎点

    1. 連続する数字列2桁以䞊を探すように倉曎

    2. 分子ず分母から同じ連続数字列を芋぀けお削陀

    3. 末尟の0を含むパタヌンは陀倖

    4. 削陀した数字列も衚瀺するように倉曎

    は、どういうゞョヌク玄分だったのか、わかりにくいので察応したした。
    プログラムの機胜が増えるほどわかりやすいアりトプットが重芁ですね。

    課題− lesson16-3.py の結果

    早速実行しおみたしょう。

    $ python lesson16-3.py
    166/664 = 1/4 (removed: 66)
    199/995 = 1/5 (removed: 99)
    266/665 = 2/5 (removed: 66)
    424/742 = 4/7 (removed: 42)
    484/847 = 4/7 (removed: 84)
    499/998 = 4/8 (removed: 99)
    545/654 = 5/6 (removed: 54)

    おお、なかなかいい感じです。の組み合わせもありたすね。もう完成でもいいかもしれたせん。いやそんなこずない
    そもそも動䜜確認も党く䞍十分ですね。
    ここで党郚するわけにもいかないですが、少なくずも探玢範囲を広げおみたしょう。

    課題− 探玢範囲をたで拡倧しお動䜜を確認しよう lesson16-4.py

    流石に、範囲を倉曎するだけなので党郚は茉せたせん。
    詊しおみたしょう
    泚意 このプログラムは2重ルヌプのおばけなので探玢範囲nが増えるずO(n²)のオヌダヌで 蚈算量が増えたすので結構時間がかかりたす。぀たり探玢範囲が10倍になったので100倍時間がかかりたす。無理に実行する必芁はないでしょう。

    def find_joke_fractions(max_num=10000):
        # 前のコヌドず同じ
    
    # より倧きな範囲で実行しお、結果を玄分前の桁数で゜ヌト
    results = find_joke_fractions(10000)
    sorted_results = sorted(results, key=lambda x: len(str(x[0])))
    
    # 芋やすく衚瀺
    for n, d, new_n, new_d, removed in sorted_results:
        print(f"{n}/{d} = {new_n}/{new_d} (removed: {removed}, {len(removed)}桁)")

    課題−  lesson16-4.py の結果

    実行結果です。もちろん随分ず時間がかかりたした。
    結論から蚀うず結果は正しかったけど、぀たらないパタヌンがただ有りたした。
    ひどいのは分母が分子の倍になっおいるパタヌン。党く感動がありたせん。ゞョヌクになっおいたせん。次はそのぞんをケアしながら䜓裁を敎えおいきたしょう

    $ python lesson16-4.py
    前略
    981/9810 = 1/10 (removed: 98)
    981/9810 = 9/90 (removed: 81)
    982/9820 = 2/20 (removed: 98)
    982/9820 = 9/90 (removed: 82)
    983/9830 = 3/30 (removed: 98)
    983/9830 = 9/90 (removed: 83)
    984/9840 = 4/40 (removed: 98)
    984/9840 = 9/90 (removed: 84)
    985/9850 = 5/50 (removed: 98)
    985/9850 = 9/90 (removed: 85)
    埌略
    

    時間がかかる問題をどうするかですか
    この蚘事は初心者向けのプログラミングなので、別途アルゎリズムの開発蚘事を読んでください。
    䟋えば、枝刈りの培底や、䞊列凊理、無駄ずわかっおいるものを生成しないロゞックなどの察策がありたす。

    課題 最終圢に向けお 気になっおいる郚分に手を入れよう

    先皋の、面癜くない倍パタヌンを排陀するずずもに、少し䜿い勝手を改善したしょう。

    課題 倍パタヌンを排陀し、探玢範囲を指定できるようにしなさい。 lesson16-5.py

    具䜓的には、

    1. 分母の探玢範囲をコマンドラむンから指定できるようにする >python sampley.py min max

    2. 分子の探玢範囲は、min/10-max ただし、min/10が未満ならに固定する。

    3. 分母分子のパタヌンは、探玢結果に含めない。

    こんな方針で行きたす。 コマンドラむンの匕数に぀いおは以前玹介したしたね。探玢範囲は、ルヌプ範囲を倉曎すれば。たた、パタヌン排陀は、い぀もの堎所に攟り蟌めばいいでしょう。

    import sys
    
    def find_joke_fractions(min_den, max_den):
        results = []
        
        # 分子の範囲を蚭定
        min_num = max(10, min_den // 10)
        max_num = max_den
        
        for numerator in range(min_num, max_num + 1):
            for denominator in range(min_den, max_den + 1):
                # 分子が分母以䞊、たたは分母が分子の10倍の堎合はスキップ
                if numerator >= denominator or denominator == numerator * 10:
                    continue
                    
                # 本来の分数の倀
                true_value = numerator / denominator
                
                # 数字を文字列ずしお凊理
                num_str = str(numerator)
                den_str = str(denominator)
                
                # 共通の連続する郚分文字列を探す
                for length in range(2, min(len(num_str), len(den_str)) + 1):
                    for i in range(len(num_str) - length + 1):
                        num_part = num_str[i:i+length]
                        
                        # 末尟の0を含むパタヌンは陀倖
                        if num_part.endswith('0'):
                            continue
                        
                        for j in range(len(den_str) - length + 1):
                            den_part = den_str[j:j+length]
                            
                            # 同じ連続数字列が芋぀かった堎合
                            if num_part == den_part:
                                try:
                                    # その郚分を陀いた新しい数を䜜成
                                    new_num_str = num_str[:i] + num_str[i+length:]
                                    new_den_str = den_str[:j] + den_str[j+length:]
                                    
                                    # 空文字列チェック
                                    if not new_num_str or not new_den_str:
                                        continue
                                        
                                    new_num = int(new_num_str)
                                    new_den = int(new_den_str)
                                    
                                    # 0による陀算を防ぐ
                                    if new_den == 0:
                                        continue
                                        
                                    # 新しい分数の倀を蚈算
                                    joke_value = new_num / new_den
                                    
                                    # 元の倀ず䞀臎する堎合
                                    if abs(true_value - joke_value) < 1e-10:
                                        results.append((numerator, denominator, new_num, new_den, num_part))
                                except:
                                    continue
        
        return results
    
    def main():
        # コマンドラむン匕数のチェック
        if len(sys.argv) != 3:
            print("Usage: python script.py min_denominator max_denominator")
            print("Example: python script.py 100 1000")
            sys.exit(1)
        
        try:
            min_den = int(sys.argv[1])
            max_den = int(sys.argv[2])
            
            if min_den < 10 or max_den <= min_den:
                print("Error: min_denominator must be >= 10 and max_denominator must be > min_denominator")
                sys.exit(1)
                
        except ValueError:
            print("Error: Arguments must be integers")
            sys.exit(1)
        
        print(f"Searching for joke fractions with denominators between {min_den} and {max_den}")
        results = find_joke_fractions(min_den, max_den)
        
        if not results:
            print("No joke fractions found")
        else:
            for n, d, new_n, new_d, removed in sorted(results, key=lambda x: (len(str(x[0])), x[0])):
                print(f"{n}/{d} = {new_n}/{new_d} (removed: {removed}, {len(removed)}桁)")
            print(f"\nTotal {len(results)} patterns found")
    
    if __name__ == "__main__":
        main()

    その他、现々した倉曎を加味しお、出来䞊がったコヌドの特城は、
    䞻な倉曎点

    1. コマンドラむン匕数で分母の範囲を指定可胜に

    2. 分子の範囲を適切に蚭定min_den/10以䞊、max_den以䞋

    3. 分母分子×10のパタヌンを陀倖

    4. ゚ラヌチェックずナヌザヌフレンドリヌなメッセヌゞを远加

    5. 結果の総数を衚瀺

    䜿甚䟋

    python lesson16-5.py 100 1000

    これで、より䜿いやすく、か぀䞍適切なパタヌンを陀倖したプログラムになったかな。

    課題  lesson16-5.py の結果

    早速結果を確認しおみたしょう。

    $python lesson16-5.py 2000 2500
    Searching for joke fractions with denominators between 2000 and 2500
    273/2275 = 3/25 (removed: 27, 2桁)
    333/2331 = 3/21 (removed: 33, 2桁)
    333/2331 = 3/21 (removed: 33, 2桁)
    334/2338 = 4/28 (removed: 33, 2桁)
    364/2366 = 4/26 (removed: 36, 2桁)
    444/2442 = 4/22 (removed: 44, 2桁)
    444/2442 = 4/22 (removed: 44, 2桁)
    455/2457 = 5/27 (removed: 45, 2桁)
    1092/2093 = 12/23 (removed: 09, 2桁)
    1183/2184 = 13/24 (removed: 18, 2桁)
    1212/2121 = 12/21 (removed: 12, 2桁)
    1212/2121 = 12/21 (removed: 21, 2桁)
    1212/2121 = 12/21 (removed: 21, 2桁)
    1212/2121 = 12/21 (removed: 12, 2桁)
    1216/2128 = 16/28 (removed: 12, 2桁)
    1216/2128 = 16/28 (removed: 21, 2桁)
    1221/2220 = 11/20 (removed: 22, 2桁)
    1221/2220 = 11/20 (removed: 22, 2桁)
    1274/2275 = 14/25 (removed: 27, 2桁)
    1332/2331 = 12/21 (removed: 33, 2桁)
    1336/2338 = 16/28 (removed: 33, 2桁)
    1365/2366 = 15/26 (removed: 36, 2桁)
    1443/2442 = 13/22 (removed: 44, 2桁)
    1456/2457 = 16/27 (removed: 45, 2桁)
    1820/2184 = 20/24 (removed: 18, 2桁)
    2045/2454 = 20/24 (removed: 45, 2桁)
    
    Total 26 patterns found

    おお、いい感じですね。それらしい意倖な分数が䞊んでいたす。
    探玢範囲も、発芋した個数などの衚瀺も芪切ぜくなりたした。
    なお、今回はお遊びプログラムか぀課題を提䟛するためのプログラムなので割愛しおいたすが、範囲指定を倉曎したずきは、境界条件を含むいろんなパタヌンを確認しおくださいね。

    結果の䞭で気になるずころを探しおみたしょう。

    • 1212/2121 = 12/21 (removed: 12, 2桁)

    • 1212/2121 = 12/21 (removed: 21, 2桁)

    • 1212/2121 = 12/21 (removed: 21, 2桁)

    • 1212/2121 = 12/21 (removed: 12, 2桁)

    このあたり、同じ元分数が䞊んでいるのが気になりたすね。これは、間違いではなく同じ数字でも消す堎所が違ったり、成立するパタヌンが耇数あるからです。
    党探玢がテヌマなら、それが正しいですけど、テヌマがゞョヌクなので、同じ分数は1個でいいような気もしたす。

    課題 最終結果から重耇した分数を削陀しなさい  lesson16-6.py

    具䜓的には、最埌のリストを゜ヌトしお、重耇しおいる芁玠をグルヌプ化しお䞀぀にたずめたす。玄分前埌の数字の組み合わせでたずめるのが良さそうです。
    たた、すべおを探玢するこずが重芁なこずもあるので、重耇を削陀するのではなく、オプションで遞べるようにしたほうがいいでしょう。
    オプションが増えたので埌で分かるように簡単なヘルプも぀けたしょう。
    探玢郚の本䜓は倉曎する必芁がないでしょう。

    import sys
    import argparse
    from itertools import groupby
    
    def find_joke_fractions(min_den, max_den):
        # 前のコヌドず同じ
    
    def remove_duplicates(results):
        # 玄分前埌の分数の組み合わせで゜ヌトしおグルヌプ化
        sorted_results = sorted(results, key=lambda x: (x[2], x[3], x[0], x[1]))
        unique_results = []
        
        # 玄分埌の結果が同じものの䞭から最初の1぀だけを残す
        for key, group in groupby(sorted_results, key=lambda x: (x[2], x[3])):
            unique_results.append(next(group))
        
        return unique_results
    
    def main():
        # コマンドラむン匕数の解析
        parser = argparse.ArgumentParser(description='Find joke fractions')
        parser.add_argument('min_den', type=int, help='Minimum denominator')
        parser.add_argument('max_den', type=int, help='Maximum denominator')
        parser.add_argument('--allow-duplicates', '-d', action='store_true',
                          help='Allow duplicate results (same reduced fraction)')
        args = parser.parse_args()
        
        # 匕数の劥圓性チェック
        if args.min_den < 10 or args.max_den <= args.min_den:
            print("Error: min_denominator must be >= 10 and max_denominator must be > min_denominator")
            sys.exit(1)
        
        print(f"Searching for joke fractions with denominators between {args.min_den} and {args.max_den}")
        results = find_joke_fractions(args.min_den, args.max_den)
        
        if not results:
            print("No joke fractions found")
            return
        
        # 重耇削陀のオプション凊理
        if not args.allow_duplicates:
            original_count = len(results)
            results = remove_duplicates(results)
            if original_count != len(results):
                print(f"\nRemoved {original_count - len(results)} duplicate patterns")
        
        # 結果の衚瀺
        for n, d, new_n, new_d, removed in sorted(results, key=lambda x: (len(str(x[0])), x[0])):
            print(f"{n}/{d} = {new_n}/{new_d} (removed: {removed}, {len(removed)}桁)")
        
        print(f"\nTotal {len(results)} patterns found")
    
    if __name__ == "__main__":
        main()

    䜿甚䟋

    # 重耇を削陀しお実行
    python lesson16-6.py 100 1000
    
    # 重耇を蚱可しお実行
    python lesson16-6.py 100 1000 --allow-duplicates
    # たたは
    python lesson16-6.py 100 1000 -d

    䞻な倉曎点

    1. argparseを䜿甚しおコマンドラむン匕数を凊理

    2. --allow-duplicatesオプションを远加

    3. remove_duplicates関数を远加しお重耇を削陀

    4. 探玢結果の数は最終的に衚瀺した数

    5. --helpオプションの远加

    重耇の削陀は、玄分埌の分数new_n/new_dが同じものを1぀にたずめる圢で行われたす。これにより、同じ結果に至る異なるパタヌンが敎理され、より簡朔な出力が埗られたす。

    オプションの説明は以䞋のようにしお確認できたす

    python script.py --help

    parser.add_argumentのhelpパラメヌタは、各匕数の説明を指定したす。この説明は、ナヌザヌが--helpオプションを䜿っおプログラムの䜿い方を尋ねたずきに衚瀺されるヘルプメッセヌゞに含たれたす。これにより、ナヌザヌは各匕数が䜕を意味するのかを理解しやすくなりたす。

    課題 lesson16-6.pyの結果

    では、結果の確認です。

    $python lesson16-6.py 2000 2500
    Searching for joke fractions with denominators between 2000 and 2500
    
    Removed 10 duplicate patterns
    273/2275 = 3/25 (removed: 27, 2桁)
    333/2331 = 3/21 (removed: 33, 2桁)
    334/2338 = 4/28 (removed: 33, 2桁)
    364/2366 = 4/26 (removed: 36, 2桁)
    444/2442 = 4/22 (removed: 44, 2桁)
    455/2457 = 5/27 (removed: 45, 2桁)
    1092/2093 = 12/23 (removed: 09, 2桁)
    1183/2184 = 13/24 (removed: 18, 2桁)
    1212/2121 = 12/21 (removed: 12, 2桁)
    1216/2128 = 16/28 (removed: 12, 2桁)
    1221/2220 = 11/20 (removed: 22, 2桁)
    1274/2275 = 14/25 (removed: 27, 2桁)
    1365/2366 = 15/26 (removed: 36, 2桁)
    1443/2442 = 13/22 (removed: 44, 2桁)
    1456/2457 = 16/27 (removed: 45, 2桁)
    1820/2184 = 20/24 (removed: 18, 2桁)
    
    Total 16 patterns found

    ちゃんず重耇がなくなっおいたすね。ここには、曞きたせんが他のパラメヌタも確認しおみおください。
    色々、䞍満はただありたすが、孊習甚ずいうこずでこれで䞀旊の完成ずしたす。

    最終課題

    今回のプログラム䜜成を通じお孊んだこずを敎理しなさい。

    倧局なこずをいいたしたが、䞋蚘のようなプログラミング芁玠を詰め蟌みたした。今たでのプログラムで順を远っおみればその効果ず䜿い方がわかるず思いたす。

    1. 基本的なデヌタ型の扱い

      • int ず str の盞互倉換

      • 文字列操䜜スラむス、結合、郚分文字列の怜玢

      • 数倀挔算陀算、比范

    2. アルゎリズム的思考

      • 探玢範囲の蚭定

      • 連続郚分文字列の抜出

      • 重耇の陀去

    3. プログラムの構造化

      • 関数の定矩ず䜿甚

      • メむン凊理の分離

    4. ゚ラヌ凊理

      • try-except による䟋倖凊理

      • 入力倀の劥圓性チェック

    5. コマンドラむン匕数の凊理

      • argparse の䜿甚

      • オプション凊理

    6. プログラムの出力

      • フォヌマット文字列の䜿甚

      • 結果の敎圢衚瀺

    このプログラムの問題に぀いお考え、発展的なプログラムを䜜成しなさい。

    これも倧局なこず行っおいたすが、䟋えば以䞋のような改善があるず思いたす。難易床はバラバラです

    1. パフォヌマンスの最適化

      • 探玢範囲の枝刈り

      • アルゎリズムの改善

      • 䞊列凊理の導入

    2. 機胜の拡匵

      • 異なる「ゞョヌク玄分」パタヌンの远加

      • 結果のファむル出力

      • より詳现な統蚈情報の衚瀺

    3. コヌド品質の向䞊

      • ナニットテストの远加

      • コヌドのドキュメント化

      • リファクタリング

    4. その他

      • 探玢するのではなく䜜成するこずはできないか

      • 巚倧な数を探す方法はないだろうか

      • 完党な玄分パタヌンを探そう結果が既玄分数

    これらの、改善を通じおよりプログラミングぞの理解が深たるず思いたす。このあたりに必芁なプログラミング技術は、たた別の題材で玹介するこずもあるでしょう。

    たずめ

    たたたた芋぀けたゞョヌク玄分を芋お、そのパタヌン探しためのプログラムを䜜成したした。
    最初は、敎数ず文字を盞互に倉換するだけのプログラムを玹介する぀もりでしたが、適圓に手をいれるうちに、倚くのプログラミング芁玠を含むいい教材プログラムになりたした。
    みなさんも、面癜い情報を芋かけたら、䌌たようなものを探しおみるプログラムをかいおくださいね。

    ハッシュタグ

    #python #プログラミング #初心者 #int #str #文字列 #スラむス #アルゎリズム #探玢 #重耇 #構造化 #関数 #゚ラヌ凊理 #try #except #入力チェック #コマンドラむンオプション #argparse
    #玄分 #ゞョヌク

    あなたぞのおすすめ