コンピュータサイエンス第一 第4週

  1. 先週の復習
  2. 条件式について・つづき
  3. リストとは?
  4. リストの応用例
  5. 本日の課題

雑談

木はスゴイということについて。

0. 先週の復習

練習問題.
次のプログラムの出力を予測せよ:
  1. a = 1
    b = 0
    while b < 5:
        a = a * 2
        b = b + 1
    print(f"a={a}")
    
  2. x = 0
    y = 32
    while y > 1:
        x = x + 1
        y = y // 2
    print(f"x={x}")
    
  3. i = 0
    while i <= 10:
        print(f"i={i % 3}")
        i = i + 1
    
練習問題.
次のプログラムが何をするか、日本語で説明せよ:
ok = 0
while ok == 0:
    x = int(input("password?"))
    if x == 1234:
        print("good")
        ok = 1
    else:
        print("bad")

1. 条件式について・つづき

1.1. not による否定

ある条件式があるとき、その条件式の「否定」は以下のようにして表せる:

構文:
if not (条件式1):
    条件式1が真でないときに実行される文
    ...
例1:
if not (x < 0):
    print("x is non-negative.")
これは、以下と同じである:
if x >= 0:
    print("x is non-negative.")
練習問題.

つぎの not を含んだ条件式を、 not を含まない条件式に直せ:

  1. not (a != b)
  2. not (y > x)
  3. not (1 <= 0)

1.2. and, or による組み合せ

複数の条件式を andor 演算子によって 組み合わせることができる。

構文:
if (条件式1) and (条件式2):
    条件式1および条件式2両方が真のときに実行される文

if (条件式1) or (条件式2):
    条件式1または条件式2一方が真のときに実行される文
例1:
if (a < 0) and (b < 0):
    print("both a and b are negative.")
例2:
if (10 <= x) and (x <= 20):
    print("x is between [10,20].")
例3:
if (0 < a) or (0 < b):
    print("either a or b is positive.")
例4:
if (x < 10) or (20 < x):
    print("x is out of [10,20].")
例5:
if ((10 <= x) and (x <= 20)) or (y == 0):
    print("x is between [10,20] or y is zero")
例6:
if (a == 1) and (a != 1):
    print("impossiburu!")
練習問題.
  1. a=2, b=-1 のとき、 (0 < a) and (0 < b) は成り立つか?
  2. a=3, b=4 のとき、 (0 < a) or (0 < b) は成り立つか?
  3. (i <= 10) and (i <= 20) を簡単にせよ。
  4. not ((x == 0) and (y == 0))and ではなく or を使って表せ。

2. リストとは?

たとえば以下のようなプログラムを考えてみる:

vote1.py
# 3人の得票数をゼロにする。
a = 0
b = 0
c = 0
x = 1
while x != 0:
    # 数をひとつ入力する。
    x = int(input("vote?"))
    if x == 1:
        a = a + 1  # 1が入力された場合。
    elif x == 2:
        b = b + 1  # 2が入力された場合。
    elif x == 3:
        c = c + 1  # 3が入力された場合。
# 3人の得票数を表示する。
print(f"a={a}")
print(f"b={b}")
print(f"c={c}")
if文 (パターン3):
if〜else のパターンをさらに発展させたもの。
if 条件式1:
    条件式1が真であるときに実行される文
elif 条件式2:
    条件式2が真であるときに実行される文
elif 条件式3:
    条件式3が真であるときに実行される文
    ...
else:
    すべての条件式が真でなかったときに実行される文

2.1. 通常の変数を使うとなにが問題か?

上の例では、候補者それぞれに a, b, c という変数を使っていた。 もし候補者が10人とか、100人だったらどうする?

アホな方法:
v1 = 0
v2 = 0
...
v100 = 0
...
if x == 1:
   v1 = v1 + 1  # 1が入力された場合。
elif x == 2:
   v2 = v2 + 1  # 2が入力された場合。
...
elif x == 100:
   v100 = v100 + 1  # 100が入力された場合。

ここでは、av1 などの決まった名前の変数ではなく、 「“i番目の変数”に代入する」などと言えるようにしたい。 これを可能にするのがリスト (list) である。 (一般的には、配列 (array) とか ベクタ (vector) などとも呼ぶ。)

2.2. リストの使い方

構文:
例1:
a = [0, 0, 0, 0]
a[0] = 4
a[1] = 6
a[2] = 4
a[3] = 9
x = a[1]  # x は 6 になる

リストの中の各変数を要素 (element) と呼ぶ。 また、リストの要素はつねに 0番目から始まる

例2:
a = [4, 6, 4, 9]
print(a[0], a[1], a[2], a[3])

リストの中身を直接書いてもよい。

例3:
a = [4, 6, 4, 9]
i = 0
while i <= 3:
    print(a[i])
    i = i + 1

ループの中でリストを使うことにより、 リストai番目の要素 を表示できる。

例4:
b = [4, 6, 4, 9]
x = 0
while x <= 3:
    print(b[3 - x])
    x = x + 1

リストの添え字として、式を使ってもかまわない。 また、リスト名や添え字として任意の変数名を使うことができる。

例5:
a = [4, 6, 4, 9]
print(a[7])  # エラー!
a[4] = 2     # エラー!

存在しない要素を代入・参照することはできない。 また、添え字はつねに 0 から始まるので、 4個の要素があるリストの場合、添え字の範囲は 0 〜 3 である。

例6:
a = [4, 6]
b = 9
print(a + b)  # エラー!

リスト名と変数名は区別すること。 一般的には、リストと通常の整数を演算することはできない。

例7:
a = [4, 6]
b = [4, 9]
c = a + b

リストどうしは + 演算子を使って連結することができる。

例8:
z = [4, 6, 4, 9, 7]
print(len(z))  # 5を表示する。

len() 関数を使うことで、リストの長さを知ることができる。

vote2.py (リストを使ったバージョン)
##  投票集計プログラム

# 3人の得票数をゼロにする。
votes = [0, 0, 0]
x = 1
while x != 0:
    # 数をひとつ入力する。
    x = int(input("vote?"))
    # x番目の得票数を増やす。
    votes[x] = votes[x] + 1
# 3人の得票数を表示する。
i = 0
while i < 3:
    print(votes[i])
    i = i + 1
演習 4-1.
  1. 上のプログラム vote2.py を入力・実行せよ。 正しく動くか?
  2. このプログラムは、候補者の番号として 1〜3 ではなく、 0〜2 を入力しなければならない。 これを 1〜3 で正しく動くようにプログラムを修正せよ。
  3. 3人ではなく、10人の候補者を扱えるようにプログラムを変更せよ。

3. リストの応用例

リストはコンピュータにおける 処理の中心ともいえる機能であり、さまざまな用途が存在する。

3.1. ベクトルとして利用する

vector.py
# ベクトルの計算
p = [-2, 3]  # (X座標, Y座標)
q = [1, 4]   # (X座標, Y座標)
r = [p[0]+q[0], p[1]+q[1]]  # ベクトルの和
n = p[0]*q[0] + p[1]*q[1]   # ベクトルの内積

3.2. データベースとして利用する

booking.py
##  座席予約システム
##  0〜4 の座席番号を与える。

# 5個の座席を仮定する。
seats = [0, 0, 0, 0, 0]
while True:  # 0 < 1 などと同じ (永久にくりかえす)
    # 座席番号を入力する。
    n = int(input("seat?"))
    if seats[n] == 0:
        # 空席の場合。
        print("available.")
        # その席を「占有」にする。
        seats[n] = 1
    else:
        # ふさがっていた。
        print("unavailable.")

3.3. 画像を格納する

anim2.py (リストを使ったバージョン)
# アニメーションをおこなう

import time
img = [0,0,0,0,0,0,0,0,0,0]
# 最初の画像。
img[0] = 1000000000000000000000000000
img[1] = 1000000000110000110000000000
img[2] = 1000000000110000110000000000
img[3] = 1000000000000000000000000000
img[4] = 1000001100000000000011000000
img[5] = 1000000110000000000110000000
img[6] = 1000000011000000001100000000
img[7] = 1000000000111111110000000000
img[8] = 1000000000000000000000000000
img[9] = 1000000000000000000000000000
t = 0
while t < 30:
    i = 0
    # img[0] 〜 img[9] を表示。
    while i < 10:
        print(img[i])
        i = i + 1
    # img[0] 〜 img[9] をずらす。
    while i < 10:
        img[i] = img[i] // 10
        i = i + 1
    time.sleep(0.1)
    t = t + 1

3.4. 集合として利用する

falling.py
# 落第者リスト
rakudai = [1234, 4567, 7890, 1111, 9999]
# 学籍番号を入力する
gakuseki = int(input("gakuseki?"))
i = 0
while i < 5:
    # どれかの番号に一致したら留年。
    if gakuseki == rakudai[i]:
        print("あなたは留年です。")
    i = i + 1

4. 本日の課題

小課題 2.

小課題 2. maxi.py を完成させる
maxi.py

このプログラムの方針:

# リストの最大値を求める
a = [-3, 8, 19, -4]
maxi = 0
i = 0
while i < len(a):
??? ...
print(f"max index = {maxi}") print(f"max value = {a[maxi]}")

中課題 3. (実際には2番目)

中課題 3. 循環小数の「循環」を検出するプログラム
frac1.py (未完成版)

これは入力した値 x に対して、 1 ÷ x の小数部分を表示するものである (x > 1 とする)。

##  筆算を使って10進数の割り算をおこなう
##  入力された値xに対して1/xの小数を表示する。
##  バグ: 循環小数だと永久に止まらない。
a = 1
x = int(input("x?"))
a = a % x
# 余りがゼロになるまで続ける。
while a != 0:
    a = a * 10
    d = a // x   # 商を求める。
    a = a % x
    print(f"digit={d}, remainder={a}")

まず、上のプログラムを実行してみよう。

$ python frac1.py
x?4
digit=2 remainder=2
digit=5 remainder=0
(つまり 1÷4 = 0.25)

$ python frac1.py
x?1000
digit=0 remainder=0
digit=0 remainder=0
digit=1 remainder=0
(つまり 1÷1000 = 0.001)

$ python frac1.py
x?256
digit=0 remainder=10
digit=0 remainder=100
digit=3 remainder=232
digit=9 remainder=16
digit=0 remainder=160
digit=6 remainder=64
digit=2 remainder=128
digit=5 remainder=0
(つまり 1÷256 = 0.00390625)

$ python frac1.py
x?3
digit=3 remainder=1
digit=3 remainder=1
digit=3 remainder=1
digit=3 remainder=1
...

完成版では、以下のように表示されるものとする:

$ python frac.py
x?3
digit=3 remainder=1
digit=3 remainder=1
junkan

$ python frac.py
x?7
digit=1 remainder=3
digit=4 remainder=2
digit=2 remainder=6
digit=8 remainder=4
digit=5 remainder=5
digit=7 remainder=1
digit=1 remainder=3
junkan
frac.py (未完成版)
##  筆算を使って10進数の割り算をおこなう
##  入力された値xに対して1/xの小数を表示する。
##  循環小数を検出して止まる。
a = 1
x = int(input("x?"))
a = a % x
# 20個分の余りを記録できるようにする。
r = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
# 余りがゼロになるか、循環するまで続ける。
while        ???       :
    a = a * 10
    d = a // x   # 商を求める。
    a = a % x
    print(f"digit={d}, remainder={a}")
??? ...
if 循環した: print("junkan")

便利な小技

画面があっという間にスクロールしてしまうとキツイので、 作業中は以下のようにするとよい:

  1. ループの途中で time.sleep(1) を入れて、表示を遅くする。
    import time
    ...
    while a != 0:
        ...
        print(f"digit={d}, remainder={a}")
        time.sleep(1)
    
  2. たとえ無限にループしても20桁で止めるようにしておく。 (注意: これだけでは正解とはみなしません)
    i = 0
    ...
    while a != 0 and i < 20:
        ...
        i = i + 1
    

Yusuke Shinyama