プログラミング入門I
2024.12.16
多重ループ

Back to index page



  1. 本日の作業内容

  2. 前回の確認テストについて

    エラーもたくさん出ましたが,やっかいなのは無限ループです.エラーや無限ループになるものは出さないで下さい.どうせ採点しませんので.

    無限ループ: b2412 b2424 b2448

    実行時エラー: b2407 b2416 b2428 b2438 b2446 b2459

    全体的には,無駄に変数を置く癖がついてしまっている人が多く,無駄な代入やそのための間違った処理などに繋がっているようです.while 文で変数 i を使用するのは,その i が順番に1ずつ増えていくなどの処理が含まれる場合です.そうでないのなら,実際の処理に必要な変数を用意するだけです.

    以下は問題のあるプログラムの例です.参考にしてください.

    n = random.randint(100,200)
    counter = n
    

    無駄な変数の置き換えをしていますが,それにしても変数名が counter

    random_number = random.randint(100, 200)
    print(random_number, end=" ")
    while random_number > 1:
        random_number //= 2
        print(random_number, end=" ")
    

    print 文が2回でてきますが,無駄ですね.

    i = 1
    while num >= i:
        print(num, end = ' ')
    
        num //= 2
    else:
        print()
    

    この変数 i も無駄ですね.

    while num1 >= 1:
        num1 /= 2
        print(num1, end =' ')
    

    問題文の中にわざわざ整数型の演算と書いてあるのに,実数型で割り算するから下のようになる.

    64.5 32.25 16.125 8.0625 4.03125 2.015625 1.0078125 0.50390625 
    

    digit = random.randint(100,200)
    while digit >= 1:
        print(f'{digit}',end = ' ')
        num = digit // 2
        digit = num
    

    これも無駄な置き換えになっています.

    num1 = random.randint(100, 200)
    while  num1 <= 1:
        print(num1, end = ' ')
        num1 //= 2
    else :
        print()
    

    num1 の値は100よりも大きいので,while 文の条件式は当然偽となり,1回も実行されません.このパターンが何人かに見られました.

    i=1
    while  i>=1:
        print(random.randint(100,200),end=' ')
    
        i//=2
    else:
        print()
    

    i の初期値が1なので,1回だけしか実行しません.

    number = random.randint(100, 200)
    
    
    
    while number > 1:
        number //= 2  
        print(number)
    

    上のような print 文は結構たくさん見られました.改行しないで1行で表示する作業は演習問題で何度もやっているのに,どうやら定着していないようです.

    99
    49
    24
    12
    6
    3
    1
    

    num = random.randint(100, 200)
    
    while num > 1:
        print(num, end = ' ')
        num //= 2
    

    上のような例も少しありました.最後の1を表示しないので,結果は下のようになります.

    168 84 42 21 10 5 2
    

    n=random.randint(100,200)
    i=1
    while i <= n:
        n/=2
        print(i,end='')
    
    

    変数 i の値は1なので,ずっと1を出し続けるというものです.

    1111111
    

    X=random.randint(100,200)
    
    while X <=+2:
        print(X,end=' ')
        X=1
    

    いろいろい意味がわからないことがあって,さっぱりわかりません.

    num1 = random.randint(100,200)
    
    while num1 > 1:
        num1 //= 2
    else:
        print()
    print(f'{num1}')
    

    最後に1回だけ num1 を print しているので,当然最後の1しか出力されませんよね.

  3. 前回の宿題について

    今回も実行時にエラーになるものがありませんでした.また,コメントアウトでエラー回避を狙ったと思われる提出もありました.エラーで無いのは助かりますので,今後も提出時にはエラーでないものを確実にアップロードするようお願いします.

    関係ないソースを提出: b2446

    出力時番号無し: b2430

    以下は例によって問題のあるプログラムの例です.参考にしてください.

    print(f"座標 P({x}, {y})")
    

    これまで何度か指摘していますが,出力様式を勝手に変えないでください.私の環境では下の表に表示が崩れます.

    □ □ □W P(2, 5)
    5 |   *   
    4 |       
    3 |       
    2 |       
    1 |       
    0 |       
      +----------
       0 1 2 3 4 5
    

    num1 = random.randint(1,5)
    num2 = random.randint(1,5)
    
    print(f'P({num1},{num2})')
    

    これも前回も指摘しましたが,変数名として num1 や num2 は適切でしょうか?今回は座標の話をしていますけど.

    これからいくつかは表示が乱れていて正しく座標を再現できていないものです.いろんなパターンがありますので,一つずつ見ていきましょう.

    x = random.randint(0, 5)
    y = random.randint(0, 5)
    
    print(f'P({x},{y})')
    
    for i in range(5, -1, -1):
        if i == 0:
            print(f'{i} +', end='')
            print('----------', end='')
        else:
             print(f'{i} |', end='')
    
        for j in range(0, 6):
            if i == y and j == x:
                print('*', end='')
            else:
                print(' ', end='')
    
        print()
        
    print('  0 1 2 3 4 5')
    

    まず発生させる乱数の値が間違っています.座標軸と干渉しないように意図的に 1 から 5 の範囲としたのに,勝手に 0 を含めているのでややこしくなります.さらに,最初に x 軸の表示をしようとしたために,y 座標が 0 だと下のようにおかしくなります.このような間違いを防ぐためには何度も実行してみて結果が大丈夫かどうかを確認しましょう.

    P(3,0)
    5 |      
    4 |      
    3 |      
    2 |      
    1 |      
    0 +----------   *  
      0 1 2 3 4 5
    

    for i in range(5,0,-1):
        print(f'{i}|')
        for j in range(1,6):
            if i == y and j == x:
                print(' *',end = '')
            else:
                print('  ',end = '')
    print('0+----------')
    print(' 0 1 2 3 4 5')
    

    for 文の最初の print でいきなり改行してしまっているので,下のように表示が崩れます.これは自分で確認できるはずなので,ちゃんと原因を究明してから提出して下さい.

    P(2,5)
    5|
       *      4|
              3|
              2|
              1|
              0+----------
     0 1 2 3 4 5
    

    print(f'P({x},{y})')
    print()
    
    num1, num2 = 5, 5
    
    for i in range(num2, -1, -1):  
        if i == 0:
            print("0+" + "-" * (2 * num1+2))
            print("   " + " ".join(str(i) for i in range(num1 + 1)))
        else:
            line = f"{i}|"
            for k in range(num1 + 1): 
                if k == x and i == y:
                    line += " *"
                else:
                    line += "  "
            print(line)
    

    なぜか x 軸の値を表示するところでおかしなスペースが入っているために,次の for 文の反復回数まで多すぎる結果になり,下のように y 軸の x 座標が 0 ではないという間違った座標表現になってしまいます.このような例は結構見られましたが,皆さんはこれまでさんざん xy 座標系を見てきたはずなのに,どうなってしまったのでしょうか?

    P(4,5)
    
    5|         *  
    4|            
    3|            
    2|            
    1|            
    0+------------
       0 1 2 3 4 5
    

    # xy平面の描画
    print("\n5|")
    for i in range(5, 0, -1):  # y軸の値を上から下に向けて描画
        line = f"{i}|"
        for j in range(1, 6):  # x軸の値を左から右に向けて描画
            if i == y and j == x:
                line += " *"
            else:
                line += "  "
        print(line)
    
    print("0+----------")
    print("   1 2 3 4 5")
    

    なんで 0 が無い?

    P(5,4)
    
    5|
    5|          
    4|         *
    3|          
    2|          
    1|          
    0+----------
       1 2 3 4 5
    

    for i in range(5, 0, -1):
        line = f'{i}|'
        for j in range(1,6):
            if i == num2 and j == num1:
                line += '     *'
            else:
                line += ' '
                    
       
        print(line)
    print('0+----------')
    print(' 0 1 2 3 4 5')
    

    * を打つ時と打たないときで文字幅が違うので,当然表示はずれますよね.例えば下のようになりますが,これも自分で気づくはずなので試行錯誤的に調節してみても解決できたはずですが.

    P(1,5)
    
    5|     *
    4|
    3|
    2|
    1|
    0+----------
     0 1 2 3 4 5
    

    for j in range(5,0,-1):
        row = ""
        for i in range(1,6):
            if i == x and j == y:
                row += "*"
            else:
                row += " "
        print(f'{j}|{row}')
    print(' +------')
    print(' 012345')
    

    明らかに見た目が出題の出力例と違いますが,確信犯的に無視していますね.

    P(3,1)
    5|     
    4|     
    3|     
    2|     
    1|  *  
     +------
     012345
    

    for y in range(5,-1,-1):
        print(y)
    
        for x in range(0,6):
                print(f'{x:2}' ,end='')
                if x==num0 and y==num1:
                    print('*', end='')
                elif x==0:
                    print('|')
                elif y==0:
                    print('-', end='')
                else:
                    print(' ', end='')
        else:
             print()
    

    print が2回あるし,外側のものは改行までしているので,当然下のように勝手に改行が入ります.どこがどうというよりも,まずは表示させるべきものとそうでないものを整理してからにしましょう.

    P(2,1)
    
    5
     0|
     1  2  3  4  5 
    4
     0|
     1  2  3  4  5 
    3
     0|
     1  2  3  4  5 
    2
     0|
     1  2  3  4  5 
    1
     0|
     1  2* 3  4  5 
    0
     0|
     1- 2- 3- 4- 5-
    

    for i in range(5,num2,-1):
            print(f'{i}|')
    
    
    for y in range (5,0,-1):
        
        for x in range (0,6):
            if y == num2 and x==num1 :
                print(f'{y}|{'  '*num1}*')
       
    
    for j in range(num2-1,0,-1):
        print(f'{j}|')
    

    上のような例が何人かありました.一つの for 文にまとめることができるのに,for 文を3個に分けてしまっています.if の場合分けで対応する方が文字数が少なくて済みますし,プログラミング入門IIで扱う予定の複数の座標の表示になると,この方法ではできません.

    以下は絶対にやっちゃダメ!なものです.なぜダメなのかというと,反復処理を使用せずにすべての場合を自分で記述しているからです.何度も言いますが,宿題や例題で扱っているものは小さな画面でさっと結果を確認するために扱う数の大きさを限定しています.100×100や10000×10000などのサイズで座標を扱おうと思ったら下の方法ではできません.

    grid = [[' ' for _ in range(6)] for _ in range(6)]
    grid [5 - y][x] = '*'
    
    print('5|', ' '.join(grid[0]))
    print('4|', ' '.join(grid[1]))
    print('3|', ' '.join(grid[2]))
    print('2|', ' '.join(grid[3]))
    print('1|', ' '.join(grid[4]))
    print('0+----------')
    print('   0 1 2 3 4 5')
    

    for i in range(5, 0, -1):
        print(f'{i}|', end= ' ')
    
        if i in range(1, y):
            print('')
        elif i in range(y+1, 6):
            print('')
        else:
            if x==1:
                print('*')
            elif x==2:
                print('  *')
            elif x==3:
                print('    *')        #yarikatagawakaranakatta
            elif x==4:
                print('      *')
            else:
                print('        *')
    

    print(f"P({x},{y})")
    print(f'      ')
    
    print("5|", " " * (x - 1) + "*" if y == 5 else " " * 5)
    print("4|", " " * (x - 1) + "*" if y == 4 else " " * 5)
    print("3|", " " * (x - 1) + "*" if y == 3 else " " * 5)
    print("2|", " " * (x - 1) + "*" if y == 2 else " " * 5)
    print("1|", " " * (x - 1) + "*" if y == 1 else " " * 5)
    print("0+----------")
    print(" ", "0 1 2 3 4 5")
    

  4. 前回の復習

    2 重の for 文を中心に多重のループについて学習しました.前回も説明しましたが,画面に文字列を2次元的に表現するグラフや表などで重宝されるのが2重のループです.外側のループの変数が行を下に進める処理に対応し,内側の変数は各行を右に進める処理に対応しますので,それを理解した上でいろいろと考えていきましょう.

  5. 多重ループ

    今回も多重の反復処理です.今回は2次元的な表現だけでなく,数値を扱う際に2重のループが必要になるものもいくつか用意しました.引き続き演習問題を通して多重ループを学習していきましょう.

  6. 演習

    今回の演習問題です.

  7. 本日のまとめ

  8. 宿題

    宿題が公開されるのは明日火曜日10:00の予定で,締切りは来週の月曜日12月23日の10:00です.レポート提出システムを使用します.

  9. 次回の予習範囲

    次回も引き続き教科書のp.113-132の範囲を学習しますので,予習をしてきてください.

    次回は多重のループに関する確認テストがありますので,復習もしっかりとしておいてください.


目次ページに戻る