リスト

基本

リストは複数の値・オブジェクトをまとめる.要素を,で区切って並べ,全体を[ ]で囲んで作成する.

a = [0, 1, 4, 9, 16, 25, 36, 49]
a
[0, 1, 4, 9, 16, 25, 36, 49]
type(a)
list

先頭要素のインデックス番号は0.

a[0]
0
a[1]
1

リストの要素数はlen関数で取得する.

len(a)
8

要素の範囲を超えてリストにアクセスするとエラーになる.

a[8]
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-7-beec7994ef7f> in <module>
----> 1 a[8]

IndexError: list index out of range

リストの最後の要素のインデックス番号は「要素数 - 1」.

a[len(a)-1]
49

リストの要素を末尾からアクセスするため,負のインデックス番号を用いることができる.

a[-1]
49
a[-2]
36

空のリストは[]list関数で作成する.

a = []
a
[]
a = list()
a
[]

スライス

a[start:end:step]という形式で,リストの要素の部分列を抽出できる(「スライス」と呼ばれる).

  • start: 抽出を開始する要素のインデックス番号.省略された場合は0となる.

  • end: 抽出を終了する要素のインデックス番号(ただし,a[end]の要素は含まれない).省略された場合はリストの要素数となる.

  • step: 要素を抽出する間隔.省略された場合は1である.

a = [0, 1, 4, 9, 16, 25, 36, 49]

開始位置と終了位置を指定したスライス.

a[2:5]
[4, 9, 16]
a[0:3]
[0, 1, 4]

開始位置を省略したスライス.

a[:3]
[0, 1, 4]

終了位置を省略したスライス.

a[5:]
[25, 36, 49]

負のインデックス番号を用いてもよい.

a[-3:]
[25, 36, 49]

要素を取り出す間隔を指定したスライス.

a[1::2]
[1, 9, 25, 49]

間隔に-1を指定して,逆順に要素を取り出すスライス(a[5], a[4], a[3]が取り出される).

a[5:2:-1]
[25, 16, 9]

開始位置と終了位置を省略し,全ての要素を逆順に取り出すスライス.

a[::-1]
[49, 36, 25, 16, 9, 4, 1, 0]

リストの要素に対する繰り返し

a = [0, 1, 4, 9, 16, 25, 36, 49]

リストの要素に先頭から繰り返しアクセスする.

for x in a:
    print(x)
0
1
4
9
16
25
36
49

リストの要素に先頭から繰り返しアクセスすると同時に,各要素のインデックス番号を得る.

for i, x in enumerate(a):
    print(i, x, a[i])
0 0 0
1 1 1
2 4 4
3 9 9
4 16 16
5 25 25
6 36 36
7 49 49

リストの要素に末尾から繰り返しアクセスする.

for x in reversed(a):
    print(x)
49
36
25
16
9
4
1
0

リストの要素に対する操作

wd = ['mon', 'tue', 'wed', 'thu', 'fri']
wd
['mon', 'tue', 'wed', 'thu', 'fri']

リスト内の要素を変更する.

wd[1] = 'tuesday'
wd
['mon', 'tuesday', 'wed', 'thu', 'fri']

末尾に要素を追加する.

wd = ['mon', 'tue', 'wed', 'thu', 'fri']
wd.append('sat')
wd
['mon', 'tue', 'wed', 'thu', 'fri', 'sat']

指定した要素を削除する.

del wd[5]
wd
['mon', 'tue', 'wed', 'thu', 'fri']

リストを連結して,新しいリストを作成する.

d = wd + ['sat', 'sun']
d
['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']

リストをスタックと見なしてpop操作をすると,末尾の要素が取り出され,同時に末尾の要素がリストから削除される.

d.pop()
'sun'
d
['mon', 'tue', 'wed', 'thu', 'fri', 'sat']

push操作に相当するものはappend関数である.

d.append('sun')
d
['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']

要素を降順に並べたリストを新たに作成する(この場合は辞書順に並ぶ).

sorted(d)
['fri', 'mon', 'sat', 'sun', 'thu', 'tue', 'wed']

元のリスト(d)は変更されていない.

d
['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']

要素を昇順に並べたリストを新たに作成する(この場合は辞書の逆順に並ぶ).

sorted(d, reverse=True)
['wed', 'tue', 'thu', 'sun', 'sat', 'mon', 'fri']

要素を降順に並び替える.今回は,リストdの要素そのものが並び替えられる.

d.sort()
d
['fri', 'mon', 'sat', 'sun', 'thu', 'tue', 'wed']

要素を昇順に並び替える.

d.sort(reverse=True)
d
['wed', 'tue', 'thu', 'sun', 'sat', 'mon', 'fri']

ある要素がリストに含まれるかを調べる.

'sun' in d
True

ある要素がリストに含まれないかを調べる.

'sun' not in d
False

リストと参照

参照の代入

リストxを作成する.

x = ['mon', 'tue', 'wed', 'thu', 'fri']
x
['mon', 'tue', 'wed', 'thu', 'fri']

変数yを作成し,リストであるxを代入する.

y = x
y
['mon', 'tue', 'wed', 'thu', 'fri']

リストyに要素を追加してみる.

y.append('sat')
y.append('sun')
y
['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']

(予想に反し)リストxの要素も変更されている('sat''sun'が追加されている).

x
['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']

これは,代入文y = xが「変数yを定義し,変数yの参照先を変数xの参照先と一致させる」という動作を行うからである.元々,変数xはリストオブジェクトを参照していた(関連付けられていた)ので,そのリスト・オブジェクトに複数の変数xyを経由してアクセスできるようになった.ひとつのオブジェクトの実体を複数の変数xyが参照している状況であるので,いずれの変数を経由してもオブジェクトの内容を変更できるし,いずれの変数を評価しても同じ結果が得られる.

リストのコピー

先ほどと同様に,リストxを作成する.

x = ['mon', 'tue', 'wed', 'thu', 'fri']
x
['mon', 'tue', 'wed', 'thu', 'fri']

変数yを作成し,リストであるxの全体のスライスx[:]を代入する.このとき,xのリスト・オブジェクトのコピーが作成され,変数yはコピーを参照することになる.

y = x[:]
y
['mon', 'tue', 'wed', 'thu', 'fri']

先ほどと同様に,リストyに要素を追加してみる.

y.append('sat')
y.append('sun')
y
['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']

今回は,リストxの要素は変更されない.これは,変数xyが,それぞれ別のリスト・オブジェクトを参照しているからである.

x
['mon', 'tue', 'wed', 'thu', 'fri']

リストと関数の引数

引数で与えられたリストの末尾に'END'を追加する関数append_endを定義する.

def append_end(s):
    s.append('END')

以下のリストxを引数として,関数append_endを呼び出す.

x = ['one', 'two']
x
['one', 'two']
append_end(x)

すると,呼び出し元の変数であるxの内容が変化する.

x
['one', 'two', 'END']

数値や文字列を引数として関数に渡す場合と異なり,リストを引数として関数に渡すと,その関数内でそのリストに対する変更は,関数の呼び出し元にも波及する.

リストの様々な作成方法

range関数が表す範囲に対応するリストを作成するには,list関数を用いる.

a = list(range(10))
a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
a = list(range(1, 10, 2))
a
[1, 3, 5, 7, 9]

リストの要素はデータ型が異なってもよい.

b = [1, 'one', 'first']
b[0]
1
b[1]
'one'

(0を含む)自然数のリストをrange関数で作成する.

a = list(range(10))
a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

リストの内包表記

空のリストを作成する.

a2 = []
a2
[]

空のリスト(a2)に要素を追加する

for i in range(10):
    a2.append(i * 2)
a2
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

これは2の段の掛け算の結果を表している.

a2[7]
14

上記の処理はリストの内包表記を使って簡潔に書ける.ソースコードを左から”list of i times two for all i in the range of ten”のように英語読みをすると解釈しやすい.

a2n = [i * 2 for i in range(10)]
a2n
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
a2n[7]
14

3の段の掛け算も内包表記を使って簡潔に書ける.

[i * 3 for i in range(10)]
[0, 3, 6, 9, 12, 15, 18, 21, 24, 27]

内包表記を入れ子にして,掛け算表を2次元配列(リスト)として作成する.

m = [[i * j for i in range(10)] for j in range(10)]
m
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
 [0, 2, 4, 6, 8, 10, 12, 14, 16, 18],
 [0, 3, 6, 9, 12, 15, 18, 21, 24, 27],
 [0, 4, 8, 12, 16, 20, 24, 28, 32, 36],
 [0, 5, 10, 15, 20, 25, 30, 35, 40, 45],
 [0, 6, 12, 18, 24, 30, 36, 42, 48, 54],
 [0, 7, 14, 21, 28, 35, 42, 49, 56, 63],
 [0, 8, 16, 24, 32, 40, 48, 56, 64, 72],
 [0, 9, 18, 27, 36, 45, 54, 63, 72, 81]]
m[2]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
m[2][3]
6

2次元配列作成時の注意

*演算子を使うと,指定した値で初期化しながら,指定した要素数のリストを作る.

a = [0] * 10
a
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

これを拡張して,2次元配列を作ることもできるが,これは避けるべきである.

a = [[0] * 10] * 10
a
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

一見すると2次元配列が作成されたように見えるが,思わぬ落とし穴がある.以下のコードである要素を変更したつもりが,列全体の値が変更されてしまう.

a[3][5] = 2
a
[[0, 0, 0, 0, 0, 2, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 2, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 2, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 2, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 2, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 2, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 2, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 2, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 2, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 2, 0, 0, 0, 0]]

これは,[0] * 10で1次元のリスト・オブジェクトが一つだけ作成され,その唯一のオブジェクトへの参照が全てのa[.]にセットされただけであるからである.

指定したサイズのリストを作成するときに,内包表記を使うこともできる.

b = [0 for i in range(10)]
b
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

これを拡張して,2次元配列を作ることができる.

b = [[0 for i in range(10)] for j in range(10)]
b
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

こちらは,我々が通常期待する2次元配列として振る舞う.

b[3][5] = 2
b
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 2, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]