6. リスト#
6.1. 基本#
リストは複数の値・オブジェクトをまとめる。要素を,
で区切って並べ、全体を[
]
で囲んで作成する。
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)
/tmp/ipykernel_204952/767257108.py 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
[]
6.2. スライス#
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]
6.3. リストの要素に対する繰り返し#
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
6.4. リストの要素に対する操作#
wd = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday']
wd
['monday', 'tuesday', 'wednesday', 'thursday', 'friday']
リスト内の要素を変更する。
wd[1] = 'tue'
wd
['monday', 'tue', 'wednesday', 'thursday', 'friday']
末尾に要素を追加する。
wd = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday']
wd.append('saturday')
wd
['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday']
指定した要素を削除する。
del wd[5]
wd
['monday', 'tuesday', 'wednesday', 'thursday', 'friday']
リストを連結して、新しいリストを作成する。
d = wd + ['saturday', 'sunday']
d
['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']
リストをスタックと見なしてpop操作をすると、末尾の要素が取り出され、同時に末尾の要素がリストから削除される。
d.pop()
'sunday'
d
['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday']
push操作に相当するものはappend関数である。
d.append('sun')
d
['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sun']
6.5. 要素の並び替え#
要素を降順に並べたリストを新たに作成する(この場合は辞書順に並ぶ)。
sorted(d)
['friday', 'monday', 'saturday', 'sun', 'thursday', 'tuesday', 'wednesday']
元のリスト(d
)は変更されていない。
d
['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sun']
引数reverseをTrue
にセットすると、要素を昇順に並べたリストを新たに作成できる(この場合は辞書の逆順に並ぶ)。
sorted(d, reverse=True)
['wednesday', 'tuesday', 'thursday', 'sun', 'saturday', 'monday', 'friday']
並び替えにおける要素の並び順は要素に対する比較演算子<
の結果に基づく。例えば、'saturday' < 'sun'
が成り立つので、'saturday'
が'sun'
の前に並ぶ。要素を比較するときの基準を変更したいときは、引数keyを用いる。以下の例では、要素の長さ(文字数)を取得する無名関数(lambda)を定義し、それをkey引数に渡すことで、文字数の少ない要素の順に並び替えている。
sorted(d, key=lambda x: len(x))
['sun', 'monday', 'friday', 'tuesday', 'thursday', 'saturday', 'wednesday']
引数reverseと併用して、文字数の多い要素の順に並び替える例である。
sorted(d, key=lambda x: len(x), reverse=True)
['wednesday', 'thursday', 'saturday', 'tuesday', 'monday', 'friday', 'sun']
要素を降順に並び替える。今回は、リストd
の要素そのものが並び替えられる。
d.sort()
d
['friday', 'monday', 'saturday', 'sun', 'thursday', 'tuesday', 'wednesday']
要素を昇順に並び替える。
d.sort(reverse=True)
d
['wednesday', 'tuesday', 'thursday', 'sun', 'saturday', 'monday', 'friday']
引数keyに関数を指定して、要素の並べ方を変更できる。
d.sort(key=lambda x: len(x))
d
['sun', 'monday', 'friday', 'tuesday', 'thursday', 'saturday', 'wednesday']
6.6. 要素の所属検査#
ある要素がリストに含まれるかを調べる。
'sun' in d
True
ある要素がリストに含まれないかを調べる。
'sun' not in d
False
6.7. リストと参照#
6.7.1. 参照の代入#
リスト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
はリストオブジェクトを参照していた(関連付けられていた)ので、そのリスト・オブジェクトに複数の変数x
とy
を経由してアクセスできるようになった。ひとつのオブジェクトの実体を複数の変数x
とy
が参照している状況であるので、いずれの変数を経由してもオブジェクトの内容を変更できるし、いずれの変数を評価しても同じ結果が得られる。
6.7.2. リストのコピー#
先ほどと同様に、リスト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
の要素は変更されない。これは、変数x
とy
が、それぞれ別のリスト・オブジェクトを参照しているからである。
x
['mon', 'tue', 'wed', 'thu', 'fri']
6.8. リストと関数の引数#
引数で与えられたリストの末尾に'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']
数値や文字列を引数として関数に渡す場合と異なり、リストを引数として関数に渡すと、その関数内でそのリストに対する変更は、関数の呼び出し元にも波及する。
6.9. リストの様々な作成方法#
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]
6.9.1. リストの内包表記#
空のリストを作成する。
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 j in range(10)] for i 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
6.9.2. 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 j in range(10)] for i 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]]