リスト

概要

Pythonなどのプログラミング言語ではデータを管理するための様々な型を持っています。 プログラミング言語が異なっても、提供される型やその使い方に大差はありません。

リストはそのようなデータを管理するための型のなかで、最もよく利用される型のひとつです。

リスト型の特徴

オブジェクト指向のプログラミング言語では、クラスからインスタンスを作成することで処理やデータを実現します。 リストはよく利用される型ですので、クラス名を使った初期化やメソッドだけでなく、 リストのための特別なインスタンスを作成する構文や、要素を操作する構文があります。

リストの基本操作

初期化とインデックスを使った操作

リストの初期化には様々な手法があります。 よく利用されるのは「[]」にリストの要素をコンマで並べるという方法です。

>>> [1, 2, 3]
[1, 2, 3]
>>> []
[]

他にはあまり利用されませんが、listのコンストラクタを使うという方法もあります。

>>> list()
[]

コンストラクタはリスト型へのキャストにも使えます。 キャストできる型はイテレート処理できる型ですので、文字列や辞書型などはリスト型へキャストできます。

>>> list('hello')
['h', 'e', 'l', 'l', 'o']

要素の取得と代入

リストのインスタンスに続けて「[]」でインデックス番号を指定することで、要素を取得できます。

>>> a = [1, 2, 3]
>>> print(a[0])
1

取得と同様に代入も可能です。

>>> a = [1, 2, 3]
>>> a[0] = 100
>>> print(a)
[100, 2, 3]

インデックスの範囲外を参照しようとすると、エラーが発生します。

>>> a = [1, 2, 3]
>>> a[100]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range

要素をリスト末尾を基準に参照

要素の指定はインデックス番号の指定だけでなく、 マイナス記号を使うことで後ろから何番目という指定もできます。

>>> a = [1, 2, 3, 4, 5]
>>> a[-1]
5
>>> a[-3]
3

後ろからの参照も範囲外へのアクセスはエラーとなります。

>>> a = [1, 2, 3, 4, 5]
>>> a[-100]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range

リストの切り出し:スライス

リストの一部をリストとして抜き出すこともできます。 たとえば長さ10のリストから、要素3から要素8までを抜き出すといったようなものです。 切り出された元のリストには変化はありません。

これは範囲を「[前のインデックス番号:後ろのインデックス番号]」として指定します。

>>> a = [1,2,3,4,5,6,7,8,9,10]
>>> a[2:8]
[3, 4, 5, 6, 7, 8]
print(a)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

要素の指定は0をベースに数えますが、後ろの数は「指定した値-1」までを取得してきます。 上記の例ではインデックス番号2(前から3個め)からインデックス番号7(前から8番め)まで取得しています。 境界を間違いやすいので注意をしてください。

前のインデックス番号を省略すると、リストの先頭から指定したインデックス番号までを切り出します。

>>> a[:5]
[1, 2, 3, 4, 5]

これとは逆に後ろを省略すると指定したインデックス番号から最後までを切り出します。

>>> a[5:]
[6, 7, 8, 9, 10]

前のインデックス番号も後ろのインデックス番号も省略すると、そのリストをそのまま「コピー」します。

>>> a[:]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

同じ内容のインスタンスを新しく作られるので、参照渡しによる副作用を防ぐためなどに利用したりします。 ただし、いわゆる「浅いコピー」なので注意をしてください。

リスト長

複雑なプログラムではリストに対してインデックス番号を基準とした処理を書くことがよくあります。 その際にリストの範囲外へのアクセスを防ぐためにリスト長を確認することが必要です。

リスト長をを得るには組み込み関数のlenを使います。

>>> a = [1,2,3]
>>> len(a)
3
>>> a = []
>>> len(a)
0

インデックスを指定できるのは0から「リスト長-1」までとなります。 リスト長が0のリストは中身が何もないので、インデックス番号を指定して要素を参照することはできません。

in演算子

リストの中に要素が含まれているかは「in演算子」で確認します。 要素が含まれていればTrueを返し、含まれていなければFalseを返します。

使い方は「要素 in リスト」となります。

>>> a = [5,7,3,9]
>>> 3 in a
True
>>> 8 in a
False

これとは逆に「含まれないこと」を確認するためには「not in」とします。 含まれていなければTrueを返し、含まれていればFalseを返します。

>>> a = [5,7,3,9]
>>> 3 not in a
False
>>> 8 not in a
True

del演算子

リストの要素をインデックス番号を指定して削除するには「del演算子」を使います。 del演算子に続けてインスタンスとインデックス番号を指定します。

>>> a = [1,2,3,4,5]
>>> print(a[3])
4
>>> del a[3]
>>> print(a)
[1, 2, 3, 5]

マイナスを使った指定や、スライスを使った範囲指定で要素を消すこともできます。

>>> a = [1,2,3,4,5]
>>> del a[1:3]
>>> print(a)
[1, 4, 5]
>>> del a[-1]
>>> print(a)
[1, 4]

+演算子

リストとリストを結合するには+演算子を使います。 結合のベースとなるリストには変化はなく、新しく結合されたリストが作成されます。

>>> a = [1,2,3]
>>> b = [4,5,6]
>>> print(a + b)
[1, 2, 3, 4, 5, 6]
>>> print(a)
[1, 2, 3]

リストの中のリスト

リストは入れ子構造にすることができます。 リストの要素としてリストを使うということです。

>>> a = [[1,2,3], [4,5,6], [7,8,9]]

上記では外側のリストが要素として[1,2,3]と[4,5,6]及び[7,8,9]を持っています。 要素を指定するには「インスタンス[インデックス番号]」としますが、 入れ子のリストではこの指定をすると内側のリストのインスタンスを返します。 そのため「インスタンス[外側のリストのインデックス番号][内側のリストのインデックス番号]」とすることで、 内側のリストの要素を取得できます。

>>> a = [[1,2,3], [4,5,6], [7,8,9]]
>>> a[1]
[4, 5, 6]
>>> a[1][1]
5

a[1][1]はaというリストから1番目の要素のリストをとりだし、 その取り出したリストから1番目の要素を取り出すということです。

リストでつかう関数

all

any

filter

map

max

min

sum

zip

リストのメソッド

append : リスト末尾への要素の追加

リストの末尾への要素の追加はappendメソッドを使います。

>>> a = [1,2,3]
>>> a.append(4)
>>> print(a)
[1, 2, 3, 4]

insert : リストへの要素の挿入

末尾以外への要素の追加(挿入)にはinsertを使います。 insertメソッドで末尾に挿入することもできますが、インデックス番号を意識しないのであればappendを使うようにしてください。

>>> a = [1,2,3]
>>> a.insert(0, 100)
>>> print(a)
[100, 1, 2, 3]

>>> a.insert(3, 200)
>>> print(a)
[100, 1, 2, 200, 3]

>>> a.insert(5, 300)
>>> print(a)
[100, 1, 2, 200, 3, 300]

pop : 要素の取り出し

リストの要素をインデックス番号を指定して取得するには「インスタンス[インデックス番号]」とします。

参照するだけでなく、その要素を同時に消したい場合は「参照した後にdel演算子で消す」のではなく、 popメソッドを使うことが一般的です。

popメソッドの引数でインデックス番号を指定された要素はリストから削除され、 返り値として返されます。

>>> a = [1,2,3,4,5]
>>> a.pop(3)
4
>>> print(a)
[1, 2, 3, 5]

メソッドに与えるインデックス番号を省略した場合はリストの末尾の要素が取り出されます。

>>> a = [1,2,3,4,5]
>>> a.pop()
5
>>> print(a)
[1, 2, 3, 4]

count : 引数で指定した値と同じ値を持つ要素数を数える

index : 引数でした値と同じ値を持つ要素のインデックス番号を得る

remove : 要素を指定した要素の削除

del演算子を使うことでインデックス番号を指定して要素を削除することができました。 要素の中身を指定して、その要素を消すことはremoveメソッドでできます。

>>> a = ['a', 'b', 'c', 'd']
>>> a.remove('b')
>>> print(a)
['a', 'c', 'd']

存在しない要素をremoveしようとするとエラーが発生します。 存在するか分からない要素を消す場合はin演算子で存在を確認してから消して下さい。

>>> a = ['a', 'b', 'c', 'd']
>>> a.remove('hello')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: list.remove(x): x not in list

このremoveメソッドで消される要素は1つです。 引数で与えた値と同じ要素が複数ある場合は前に存在するものが消されます。

>>> a = ['a', 'b', 'c', 'd', 'b']
>>> a.remove('b')
>>> print(a)
['a', 'c', 'd', 'b']

リストの結合 : +演算子, extendメソッド

リストとリストの結合には+演算子を使った新しいリストの作成方法だけでなく、 あるリストのインスタンスに別のリストを繋げるextendメソッドもあります。

>>> a = [1,2,3,4]
>>> b = [5,6,7,8]
>>> a.extend(b)
>>> print(a)
[1, 2, 3, 4, 5, 6, 7, 8]

+演算子を使った場合は結合されるリストがそのままですが、 extendメソッドを使った場合は呼び出し元のインスタンスが変化しています。

リストに別のリストをappendしても、リストは結合されないので注意をしてください。

>>> a = [1,2,3,4]
>>> b = [5,6,7,8]
>>> a.append(b)
>>> print(a)
[1, 2, 3, 4, [5, 6, 7, 8]]

リストの反転: reverse

リストの並びを逆順にするためにはreverseメソッドを呼び出します。

>>> a = [1,2,3,4,5]
>>> a.reverse()
>>> print(a)
[5, 4, 3, 2, 1]

リストのソート: sort

リストの要素を昇順(小さいものから大きいものへ)に並び変えるには、sortメソッドを使います。

>>> a = [1,3,5,2,4]
>>> a.sort()
>>> print(a)
[1, 2, 3, 4, 5]

降順(大きいものから小さいものへ)に並び替えたい場合は、 メソッドのオプション引数で「reverse=True」を与えて下さい。

>>> a = [1,3,5,2,4]
>>> a.sort(reverse=True)
>>> print(a)
[5, 4, 3, 2, 1]

リストの初期化

リストのインスタンスを初期化する(空にする)には、clearメソッドを呼び出します。

>>> a.clear()
>>> print(a)
[]

新しく変数に空のリストを代入しても変数レベルでは初期化できます。

リストのコピー

リストのコピーはスライシングで「インスタンス[:]」とすることでもできますが、 copyメソッドを使うことでもできます。

>>> a = [1,2,3,4,5]
>>> b = a.copy()
>>> print(b)
[1, 2, 3, 4, 5]

これは「浅いコピー」と呼ばれるもので、リストの要素のインスタンスはコピー元とコピー先で共有されています。 要素のインスタンスまで新しく作成しなおすのは「深いコピー」と呼ばれており、copyモジュールを使います。

キュー(Queue)とスタック(Stack)

キュー 」及び「 スタック 」は複数のデータを管理するためのデータ構造です。 これらはモジュールを使うことで利用できますが、簡単な用途であればリストで実現できます。

キューは別名「 FIFO (First In First Out) 」とも呼ばれており、 最初にいれたデータを最初に取り出すというデータ構造です。 要素を追加するときは最後にappendし、要素を取り出す時はindexが0のものをpopします。

>>> queue = [1,2,3]
>>> queue.append(4)
>>> print(queue)
[1, 2, 3, 4]
>>> a = queue.pop(0)
>>> print(a)
1
>>> print(queue)
[2, 3, 4]

キューはリストで管理されているタスクを順に処理していくような場合に使うと便利です。

一方、スタックは「 LIFO(Last In First Out) 」と呼ばれており、 その名前が示すように最後にいれたデータを最初に取り出すというデータ構造です。

追加するときはリストに最後の要素としてappendし、 取り出す時は末尾をpopします。 popメソッドを引数なしで呼び出せば常にリスト末尾の要素を抜き出します。

>>> stack = [1,2,3]
>>> stack.append(4)
>>> print(stack)
[1, 2, 3, 4]
>>> a = stack.pop()
>>> print(a)
4
>>> print(stack)
[1, 2, 3]

スタックは後に入ってきたタスクほど優先して処理していく場合に使います。 ただ、スタックの中の要素が貯まり続けて空にならないような場合は、 スタックに最初の方にいれられた要素は残り続けてしまいます。