PyLearn02: リスト、for文

まとめて変数を管理することのできる配列という概念と、それを一括して反復処理する制御文、for文を学びます。Python3には、リストと呼ばれる大変便利な配列があるので、リストについて述べます。

はじめに、リストの宣言および初期化についてです。aはいくつかの数字が入ったリスト、bは何も入っていない空のリストとなります。

In [1]:
a=[5, 3, 2, 4]
b=[]

print("a=", a)
print("b=", b)
a= [5, 3, 2, 4]
b= []

以下のように書くと、個別の要素にアクセスできます。4つの数字が、a[0]〜a[3]のなかに入れられていることがわかります。0スタートなので注意してください。

In [2]:
print(a[0])
print(a[1])
print(a[2])
print(a[3])
5
3
2
4

a[-1]で、一番最後の要素にアクセスすることができます。ちょっと便利(?)な機能として、print関数を使わなくても、最後に記載した変数表示されます。なので、変数一つだけ表示したい場合は、print関数を使わなくても良かったりします。

In [3]:
a[-1]
Out[3]:
4

bは空のリストなので、b[0]でもアクセスすることはできません。また、a[4]もありませんので、エラーが出ます。

In [4]:
print(b[0])
print(a[4])
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-4-fbade397922a> in <module>
----> 1 print(b[0])
      2 print(a[4])

IndexError: list index out of range

以上が個別リストへのアクセスです。次に個別ではなく、一定範囲の変数にアクセスしてみます。これはコロン「:」の左右に数字を入れることで実現します。a[0]からa[3]までアクセスしたい場合には、以下のように書きます。

In [5]:
a[0:4]
Out[5]:
[5, 3, 2, 4]

a[4]ってないんじゃないんでしたっけ、っと違和感を持つと思います。「0:4」という範囲指定は、「0から4まで(0は含むが4は含まない)」となります。したがって、a[0], a[1], a[2], a[3]までが対象となります。自分が指定したい場所から1増やした値を入れる必要がある、と覚えておくと良いと思います。

コロンの左を空欄にすると「最初から」、コロンの右を空欄にすると「最後まで」と指定することができます。シャープを打つと、その右側をコメントアウトとして文字を書くことができます。

In [6]:
print(a[:2]) # a[0], a[1]
print(a[2:]) # a[2], a[3]
print(a[:])  # a[0], a[1], a[2], a[3]
[5, 3]
[2, 4]
[5, 3, 2, 4]

リストは、文字列も扱うことができます。

In [7]:
c=["今日の授業は", "数学です。"]
print(c)
print(c[0])
print(c[1])
print(c[0],c[1])
['今日の授業は', '数学です。']
今日の授業は
数学です。
今日の授業は 数学です。

リストのすごく自由度が高い機能として、数字も、文字も、関数(の使用)も、変数も、まとめて入れられるというものがあります。

In [8]:
d=[123, "りんご", len(c), c]
print(d[0])
print(d[1])
print(d[2])
print(d[3])
123
りんご
2
['今日の授業は', '数学です。']

リストの中にリストを入れることもできます。

In [9]:
e=[["あ","い"], [3,4], [5,6,7,8,9]]

リストの中にあるリストには、以下のようにアクセスします。

In [10]:
print("eの0番目にあるリストの、0番目の要素 → ", e[0][0])
print("eの0番目にあるリストの、1番目の要素 → ", e[0][1])
print("eの2番目にあるリストの、2番目から4番目の要素 → ", e[2][2:5])
eの0番目にあるリストの、0番目の要素 →  あ
eの0番目にあるリストの、1番目の要素 →  い
eの2番目にあるリストの、2番目から4番目の要素 →  [7, 8, 9]

リストの中にリストを入れる、という行為は少しわかりにくいので使いたくないかもしれません。しかし、一括した情報をまとめるのにとても便利です。例えば、3人の名前、身長、体重を一括して一つの変数としてまとめてみます。i番目の人のデータがInfo[i]に一括してまとめられているので、格段にプログラムのミスが少なくなります。こういう癖をつけておかないと、何週間もかけて開発してきたコードがぐちゃぐちゃになり、作り直しになったりするかもしれません。

In [11]:
Info = [["一郎", 150, 50], ["二郎", 160, 97], ["三郎", 170, 70]]
i=1
print(Info[i][0], "さんの身長は", Info[i][1], "cm、体重は", Info[i][2], "kgとなります。")
二郎 さんの身長は 160 cm、体重は 97 kgとなります。

次に、リストに値を入れる操作(代入)について考えてみます。以下のコードは、k[0]の値を代入する前と後で中身を見ています。中身が変わっていることを確認できます。最後に、もう一度元の値に戻しています。

In [12]:
k=[1, 2, 3]
print(k[0])
k[0]=10
print(k[0])
k[0]=1
print(k[0])
1
10
1

k[0]=1 k[1]=2 k[2]=3 ...ときたら、k[3]=4を新しく作りたいなと考えたとします。しかし、次のようにエラーが出てしまいます。

In [13]:
k[3]=4
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-13-01bd2724b61a> in <module>
----> 1 k[3]=4

IndexError: list assignment index out of range

list.append

k[0], k[1], k[2]は初めに初期化したからあるけど、k[3]は用意されてないよ、と怒られているわけです。リストにおいて、もともと用意していなかった領域に対して値を入れるには、appendというメソッドを使います。これは、リストkの一番後ろに4を追加する、という意味を持ちます。

In [14]:
k.append(4)
print(k[3])
print(k)
4
[1, 2, 3, 4]

list.sort

リストのメソッドに、ソートもあります。数字やアルファベットを並び替えてくれます。

In [15]:
r=[3,4,10,5,1,7,7]
r.sort() # ソート
print("昇順ソート(数字): ", r)
r.sort(reverse=True)
print("降順ソート(数字): ", r)

st=["か","こ","き","く", "け"]
st.sort() # ソート
print("昇順ソート(文字): ", st)
st.sort(reverse=True)
print("降順ソート(文字): ", st)

en=["c","a","d","b", "e"]
en.sort() # ソート
print("昇順ソート(英語): ", en)
en.sort(reverse=True)
print("降順ソート(英語): ", en)
昇順ソート(数字):  [1, 3, 4, 5, 7, 7, 10]
降順ソート(数字):  [10, 7, 7, 5, 4, 3, 1]
昇順ソート(文字):  ['か', 'き', 'く', 'け', 'こ']
降順ソート(文字):  ['こ', 'け', 'く', 'き', 'か']
昇順ソート(英語):  ['a', 'b', 'c', 'd', 'e']
降順ソート(英語):  ['e', 'd', 'c', 'b', 'a']

list.remove

リストの特定要素を削除するメソッドに、removeがあります。一個しか除去されないので注意しましょう。

In [16]:
st2=["a", "b", "c", "a"]
print(st2)
st2.remove('a')
print(st2)
['a', 'b', 'c', 'a']
['b', 'c', 'a']

list.extend

リスト同士をつなげる場合には、extendメソッドを使います。

In [17]:
str1=["今", "は", "何時", "ですか?"]
str2=["午前", 3, "時です。"]
str1.extend(str2)
print(str1)
['今', 'は', '何時', 'ですか?', '午前', 3, '時です。']

以上、リストのメソッドとして、append, sort, remove, extendを扱いました。他にも無数にあるので、自分で勉強してください。個人的な主観ですが、appendはかなり使います。

for文

リストはこの辺にして、次はfor文を扱ってみます。以下のコードは、iを0から8まで(ただし8は含まない)増加させながら、「print("i=", i, "-> f=", f[i])」を一回一回実行しているコードです。ですので、

print("i=", 0, "-> f=", f[0])

print("i=", 1, "-> f=", f[1])

...

print("i=", 7, "-> f=", f[7])

というコードと同じです。

In [18]:
f=[0, 2, 4, 8, 10, 12, 14, 16] # 8つの要素、f[0]~f[7]

for i in range(0, 8):
    print("i=", i, "-> f=", f[i])
i= 0 -> f= 0
i= 1 -> f= 2
i= 2 -> f= 4
i= 3 -> f= 8
i= 4 -> f= 10
i= 5 -> f= 12
i= 6 -> f= 14
i= 7 -> f= 16

このように、同じコードを何回も書かなければいけない状況を回避できます。ただし、range(0, 8)のように、「8」という数字を明示的に書くのは良くありません。何らかの実験データを扱うとき、被験者の数だけfor文を回さなくてはいけない、という状況を考えてみます。春ごろに簡易的な実験として被験者7人からデータを集め、range(0, 8)と書き、何らかの分析を実施しました。いい結果が出たので、もっと大規模にデータを取ろうとなり、50人からデータを集めたとします。このために半年の時間を要しました。半年後、プログラムを開いてみます。時間が経ったので細かいことは忘れています。まあ半年前に動いたからいいやと思い、何も考えずにこのプログラムを使いました....。とすると、アウトです。分析し直しになってしまいます。このような状況が起こりえてしまうので、range(0, 8)と明示的に書くのは、やめたほうが無難です。未来のバグ祭りが予期されます。これを回避するには、len関数を使います。以下のように書くことで、リストfのサイズが変わっても、問題なく動くことが保証されます。

In [19]:
for i in range(0, len(f)):
    print("i=", i, "-> f=", f[i])   
i= 0 -> f= 0
i= 1 -> f= 2
i= 2 -> f= 4
i= 3 -> f= 8
i= 4 -> f= 10
i= 5 -> f= 12
i= 6 -> f= 14
i= 7 -> f= 16

for文は、インデント(広いスペース)がついているところのみに適用されます。

In [20]:
for i in range(0, len(f)):
    print("iの値は", i, "です。")       # ここから
    print("fの値は", f[i], "です。")
                                        # 改行があっても問題なし
    print("*** for文の中にいます。***") # ここまでを反復

print("*********************")
print("for文が終わりました。")
iの値は 0 です。
fの値は 0 です。
*** for文の中にいます。***
iの値は 1 です。
fの値は 2 です。
*** for文の中にいます。***
iの値は 2 です。
fの値は 4 です。
*** for文の中にいます。***
iの値は 3 です。
fの値は 8 です。
*** for文の中にいます。***
iの値は 4 です。
fの値は 10 です。
*** for文の中にいます。***
iの値は 5 です。
fの値は 12 です。
*** for文の中にいます。***
iの値は 6 です。
fの値は 14 です。
*** for文の中にいます。***
iの値は 7 です。
fの値は 16 です。
*** for文の中にいます。***
*********************
for文が終わりました。

for文の反復回数の指定方法は、これ以外にもたくさんありますが、普通にプログラムを組むだけでしたら、range(a, b)でaからbまで(ただしbは含まない)繰り返せる、と覚えておくだけで困らないと思います。