.. toctree:: =============================== 5. forとwhileによる繰り返し処理 =============================== 「for」と「while」文を使って、指定した回数や指定した条件を満たす間、 繰り返し処理(ループ)を行うことができます。この回では「for」と「while」 文の使い方を身につけます。第5回講義の目的は以下のとおりです。 * forとwhileによる繰り返し処理の文法を理解する。 * forとwhileループ中で、breakとcontinueによる処理の分岐法を理解する。 for文 ===== 「 **for** 」の後に「 **カウンタ変数** 」「 **in** 」「 **リスト変数 (オブジェクト)** 」、最後に「 **:** 」を書いて改行します。ループ内の処 理はインデントでならべます。ループ内の処理はLISTの要素数だけ繰り替えさ れ、**i** にLISTの要素がループのたびに代入されます。 .. code-block:: none for i in LIST: 処理1 処理2 処理3 . . . 通常処理 . . . 「*リスト変数*」の型がリスト(オブジェクト)でない場合は、エラーになります。 for文を使って0から100までの整数を足してみます。 .. code-block:: python :caption: example-01 :linenos: total = 0 # totalの初期化 for i in range(101): # range(101)で[0, 1, 2, ... 100]を生成 total = total + i # iはループ毎に0, 1, 2,...が代入される print("0+1+2+...+100={}".format(total)) if文と組み合わせて特定の条件を満たす数字のみの合計を求めてみます。 .. code-block:: python :caption: example-02 :linenos: total = 0 for i in range(101): if (i % 3) == 0: total = total + i print("100までの数字で3で割りきれる数の合計は{}".format(total)) while文 ======= 「*while*」の後に「*条件式*」、最後に「*:*」を書いて改行します。ループ 内の処理はインデントでならべます。forと異なりリストの要素に連続アクセ スしないでループ処理する時に使います。ループ内の処理は、条件式を満たす 間(True)に繰り返されます。条件式を永遠に満たす場合、無限ループになって プログラムが終了しないので注意してください。後述するbreak文と組み合わ せてループを脱出させることができます。 .. code-block:: none while 条件式: 条件式がTrue時に実行する処理をインデントでならべる。 処理1 処理2 処理3 . . . 通常処理 . . . 1から99まで足しあげる例は以下のとおりです。 .. code-block:: python :caption: example-03 :linenos: i, total = 0, 0 # 変数の初期化 while i < 100: # i<100の間、繰り返し total = total + i # totalにiを足してupdate i += 1 # iをupdate print(total) print(sum(range(100))) # 関数を使って同じ計算 for文で行う処理はwhile文で書き直すことができます。リストの要素に連続し てアクセスする処理を行う場合はfor文、条件式でループ回数を指定したい場 合はwhile文を使います。 .. code-block:: python :caption: example-04 :linenos: total = 0 for i in range(100): # [0,...99]を作成 total = total + i # totalにiを足してupdate print(total) print(sum(range(100))) # 関数を使って同じ計算 ループのネスト ============== for文やwhile文で処理するループの中に、さらにfor文やwhile文を配置するこ とで多重のループ処理を行うことができます。九九の一覧を二重ループで表示 してみます。 .. code-block:: python :caption: example-05 :linenos: for i in range(10): # 10の位のループ for j in range(10): # 1の位のループ v = i * j # 九九の計算 print("{}*{}={}".format(i, j, i*j)) # 九九の結果を表示 .. note:: 多重ループのような繰り返し処理は、科学技術計算で頻出します。forや while文を使ったループ処理は、実行速度が遅いことが欠点です。高速にルー プ計算を行うために、後述するnumpyが開発されています。numpyを使って、 forやwhileによるループ計算をなるべく避けることがプログラムを高速化さ せるために重要になります。 ループ中での分岐処理 ==================== ループ処理中で、処理をスキップしたりループから脱出したい場合は、 continue文とbreak文が使えます。pass文は何もしない場合に使います。 .. csv-table:: :header: "命令文", "意味" :widths: 10, 40 "break", "break文のところでループから脱出する" "continue", "cotinue文以下の処理をスキップして次のループに進む" "pass", "何もしない。if, elseの分岐と組み合わせて使う" while文で無限ループを作ってif文により分岐し、break文でループを脱出させることで、 0から50までの数字の合計を求めてみます。 .. code-block:: python :caption: example-06 :linenos: i, total = 0, 0 # 初期化 while True: # 条件式がTrueなので無限ループ total = total + i # totalにiを足してupdate i += 1 # iに1を足してupdate if i > 50: # iが51になったらループを脱出 break print(total) print(sum(range(51))) # range()とsum()を使って同じ計算 whileとfor文を使って1から100までの数字で20から50の数字を除いた合計を求 めてみます。 .. code-block:: python :caption: example-07 :linenos: total = 0 # 初期化 for i in range(101): if 20 <= i and i <= 50: # 20から50の範囲かの条件チェック continue # 処理をスキップして次の要素へ total = total + i # totalにiを足してupdate print(total) print(sum(range(20)) + sum(range(51, 101))) # range()とsum()を使って同じ計算 参考にifとelse、何もしないpassを使ってcontinueを書き換えることができます。continue文を使った方が直感的かと思います。 .. code-block:: python :caption: example-08 :linenos: total = 0 # 初期化 for i in range(101): if 20 <= i and i <= 50: # 20から50の範囲かの条件チェック pass # 何もしない命令文のpass else: total = total + i # 条件を満たさない場合だけtotalをupdate print(total) print(sum(range(20)) + sum(range(51, 101))) # range()とsum()を使って同じ計算 要素番号の利用 ============== forループで要素番号と要素を一緒に利用したい場合があります。 **enumerate()** を使うとすっきり書けます。 .. code-block:: python :caption: example-09 :linenos: x = [8.082, 9.962, 4.999, 6.642, 2.251, 8.082] # リストの定義 # enumerate()を使って要素番号と要素を表示 for i, xi in enumerate(x): # 要素番号をi、要素をxiに代入 print("{}番目のデータは{}".format(i, xi)) # index()を使って要素番号と要素を表示 for xi in x: print("{}番目のデータは{}".format(x.index(xi), xi)) # 6番目が0番目になってしまうのでダメ # 面倒だが要素番号用のcntを定義して使う cnt = 0 for xi in x: print("{}番目のデータは{}".format(cnt, xi)) # 6番目が0番目になってしまう cnt += 1 また要素数と同じxとyのリストの要素に同時にアクセスしたい場合、**zip()** 関数が使えます。 .. code-block:: python :caption: example-10 :linenos: x = [8.082, 9.962, 4.999, 6.642, 2.251] y = [0.328, 0.152, 2.089, 0.159, 0.233] # zipを使って計算 for xi, yi in zip(x, y): # xiとyiに連続した要素を代入 print(xi + yi) # 各要素の足し算 # enumerateを使って計算。zipを使った方が直感的 for i, xi in enumerate(x): print(x[i] + y[i]) # 各要素の足し算 内包表記 ======== for文のルーブ処理が1行で、要素に処理を行って新しいリストを作りたい場合、 **内包表記** が使えます。要素が文字のリストをfloatに変換したい場合、内包表 記を使わなければ以下のように書きます。 .. code-block:: python :caption: example-11 :linenos: l = ["13", "1.3e-2", "5.2", "2.4", "5.6", "3.2e10"] # 文字要素のリストを定義 for i, d in enumerate(l): # enumerateで要素番号と要素にアクセス l[i] = float(d) # リストの要素をupdate print(l) 内包表記を使えばすっきり書けます。 .. code-block:: python :caption: example-12 :linenos: l = ["13", "1.3e-2", "5.2", "2.4", "5.6", "3.2e10"] # 文字要素のリストを定義 l = [float(d) for d in l ] # 各要素をfloat型へ print(l) .. 講義後に追加 ============ 大窪がメモしたファイルを置いておきます。参考にしてください。 :download:`第6回講義メモ <2018-11-14/第6回講義メモ.pdf>` .. アンケートの統計 ---------------- .. image:: 2018-11-14/statistics.png :width: 800px :align: center クイズ ====== Q1 -- 0から100の整数の中で7で割りきれる整数の総和を求める。for文とwhile文の両方で作成する。 .. .. code-block:: python :linenos: # for文で作成 total = 0 # totalの初期化 for i in range(101): if i % 7 == 0: # 7で割りきれるか調べる total += i # totalをupdate print("forを使った結果: {:d}".format(total)) # while文で作成 i, total = 0, 0 # iとtotalの初期化 while(i <= 100): if i % 7 == 0: total += i i += 1 # iのupdate print("whileを使った結果: {:d}".format(total)) Q2 -- 九九の表の中で5で割りきれる数字を表示する。 答え .. code-block:: python :linenos: for i in range(1, 10): # 10の位 for j in range(1, 10): # 1の位 if i * j % 5 == 0: # 5で割りきれるかのチェック print("{}*{}={}は5で割りきれる".format(i, j, i*j)) Q3 -- 以下のリストを要素番号付きで表示する。 .. code-block:: python s = ["B", "Al", "Ga", "In", "Tl", "Uut"] 答え .. code-block:: python :linenos: s = ["B", "Al", "Ga", "In", "Tl", "Uut"] for i, v in enumerate(s): print("要素番号, 要素={}, {}".format(i, v)) Q4 -- 以下のxとyのリストで、同じ要素番号の要素を足して作成したリストzを作る。 .. code-block:: python x = [0.56474832, 0.69283729, 0.12476153, 0.38224242, 0.10156261] y = [0.44220529, 0.17673, 0.09141826, 0.7363728, 0.95426017] 答え .. code-block:: python :linenos: x = [0.56474832, 0.69283729, 0.12476153, 0.38224242, 0.10156261] y = [0.44220529, 0.17673, 0.09141826, 0.7363728, 0.95426017] z = [] for xi, yi in zip(x, y): z.append(xi * yi) print(z) Q5 -- 0から1000までの数字で3のつく数字(3, 13, 31, 913等)の時に"ナベアツ"と表 示させる。str()とfind()を使ってください。 答え .. code-block:: python :linenos: for i in range(101): if str(i).find("3") != -1: # 文字型に変換して3が含まれるかチェック print(i, "ナベアツ") Q6 -- 以下のデータから平均値 :math:`\overline{x}` と分散 :math:`\sigma` を求める。 :math:`\overline{x}` と :math:`\sigma` を求める式は以下のとおり。 .. math:: \overline{x} &= \frac{1}{N}\sum_i^N x_i \sigma &= \frac{1}{N}\sum_i^N (\overline{x} - x_i)^2 .. code-block:: python glist = [1.05, 2.77, 1.14, 1.06, 1.57, 0.73, 2.42, 1.80, 0.18, 1.83, 1.40, 1.25, 1.76, 2.82, 0.33, 2.78, 2.42, 2.38, 2.90, 0.02, 1.36, 1.31, 0.93, 0.56, 0.08, 2.30, 0.86, 2.88, 0.00, 1.82, 0.29, 0.71, 1.17, 0.63, 2.04, 2.70, 1.95, 2.70, 1.17, 1.75, 1.42, 2.56, 0.76, 0.33, 0.91, 2.96, 0.71, 1.23, 2.91, 0.73] 答え .. code-block:: python :linenos: glist = [1.05, 2.77, 1.14, 1.06, 1.57, 0.73, 2.42, 1.80, 0.18, 1.83, 1.40, 1.25, 1.76, 2.82, 0.33, 2.78, 2.42, 2.38, 2.90, 0.02, 1.36, 1.31, 0.93, 0.56, 0.08, 2.30, 0.86, 2.88, 0.00, 1.82, 0.29, 0.71, 1.17, 0.63, 2.04, 2.70, 1.95, 2.70, 1.17, 1.75, 1.42, 2.56, 0.76, 0.33, 0.91, 2.96, 0.71, 1.23, 2.91, 0.73] ave = sum(glist)/len(glist) # 平均値の計算 std = 0 # 標準偏差の計算 for v in glist: std = std + (ave - v)**2 std = std/len(glist) # Nで割って標準偏差を求める print("平均値: {:.3f}".format(ave)) print("標準偏差: {:.3f}".format(std)) Q7 -- GPA=2.5以上の学生が何人いるか調べる。 .. code-block:: python glist = [1.05, 2.77, 1.14, 1.06, 1.57, 0.73, 2.42, 1.80, 0.18, 1.83, 1.40, 1.25, 1.76, 2.82, 0.33, 2.78, 2.42, 2.38, 2.90, 0.02, 1.36, 1.31, 0.93, 0.56, 0.08, 2.30, 0.86, 2.88, 0.00, 1.82, 0.29, 0.71, 1.17, 0.63, 2.04, 2.70, 1.95, 2.70, 1.17, 1.75, 1.42, 2.56, 0.76, 0.33, 0.91, 2.96, 0.71, 1.23, 2.91, 0.73] 答え .. literalinclude:: q7.py Q8 -- 以下のxとyのデータを含む文字列から、x+yを計算する。zの結果をprint()で出力する。 ヒント 以下の手順でプログラムを作成する。 #. 文字列dataの両端のスペースと改行コードを消す strip() #. 改行コード(\\n)でsplit()して1行1要素とする。 #. x yの行はスキップしたforループで、split()しながらxとyの値をfloatに変換する。 #. zの計算をする。 .. code-block:: none data = """ x y 0.56474832 0.44220529 0.69283729 0.17673 0.12476153 0.09141826 0.38224242 0.7363728 0.10156261 0.95426017 """ 答え .. literalinclude:: q8.py Q9 -- AからJまでの点の三次元座標データを含む以下の文字列を考える。もっとも原 点に近い点を求める。 ヒント 以下の手順でプログラムを作成する。 #. 問題8に習ってx, y, zのリストを作成する。また記号データを保持するリストもつくる。 #. forループで各点の原点からの距離を計算する。 #. forループの中でもっとも原点に近い座標の要素番号を調べる。 #. 求めた要素番号から記号の表示 .. code-block:: python data = """ x y z A 75.57 68.92 38.37 B 74.68 17.44 12.51 C 25.73 46.65 51.20 D 19.23 14.52 17.84 E 62.47 43.26 35.21 F 7.90 90.52 21.61 G 60.47 13.96 9.04 H 27.11 8.14 37.19 I 87.59 16.17 22.53 J 92.27 65.88 72.14 """ 答え(その1, 辞書データに保存してforで回して調べる) .. literalinclude:: q9.py 答え(その2, listを作成してindex()とmin()で調べる) .. literalinclude:: q9-2.py Q10 --- 以下の文章で\"千葉\"を含む行番号を表示させる。 ヒント 以下の手順でプログラムを作成する。 #. 改行コードでsplit()してリストを作る。 #. forでループしながら1行毎に千葉が含まれるかチェックする。 .. code-block:: python s = """千葉大学は、1949年(昭和24年)に千葉医科大学・同附属医学専門部・同 附属薬学専門部・千葉師範学校・千葉青年師範学校・東京工業専門学校・千葉 農業専門学校を包括して新制の国立大学として発足した。国立大学法人法によ り、2004年度には国立大学法人千葉大学となる。 新制国立大学として発足した当時は、5学部(医学部、園芸学部、学芸学部、 工学部、薬学部)から成り立っていたが、その後に学部研究科の拡充改組を重 ね、現在は10学部(国際教養学部、文学部、教育学部、法政経学部、理学部、 医学部、薬学部、看護学部、工学部、園芸学部)、11研究科(教育学研究科、 理学研究科、看護学研究科、工学研究科、園芸学研究科、融合科学研究科、人 文社会科学研究科、医学薬学府、専門法務研究科<法科大学院>、自然科学系研 究科アソシエーション)によって構成されるに至る。""" 答え .. literalinclude:: q10.py Q11 --- 以下の数値データは 関数 :math:`y=\frac{1}{3}x^2` について、ランダムな :math:`x` と :math:`y` の値を文字列で定義したデータです。 .. code-block:: none data = """ # i x y 0 -2.1020 1.4729 1 -1.8776 1.1751 2 -0.9796 0.3199 3 -0.5306 0.0938 4 -0.5306 0.0938 5 -0.3061 0.0312 6 0.8163 0.2221 7 1.7143 0.9796 8 1.9388 1.2530 9 2.3878 1.9005 10 2.3878 1.9005 11 2.3878 1.9005 12 3.5102 4.1072 13 3.5102 4.1072 14 3.7347 4.6493 15 4.1837 5.8344 16 5.5306 10.1959 17 5.9796 11.9185 18 6.6531 14.7544 19 7.3265 17.8927 """ 数値データを読み込んで、データ :math:`x`の範囲で数値積分する。図のよう に各 :math:`x_i` 点で矩形の幅と高さを求め、矩形の面積を足し合わせれば 良いです。矩形の幅は、:math:`x_i`毎に変わることに注意してください。比 較としてに :math:`x_0` から :math:`x_{19}` まで、関すを積分して求めた 数式から計算した解析解も計算しています。 .. image:: 11.png :width: 500px :align: center 答えは次の通りになります。 .. code-block:: none 矩形の近似解 = 45.16 積分式から求めた解析解 = 44.73 答え .. literalinclude:: q11.py