Python入門(6) リスト
Pythonの柔軟なプログラミングを可能としているデータ構造にリスト(list)とディクショナリがある。 リストは、1つの値ではなく、一連の値を格納しておくための変数で、他の言語では配列と呼ばれているものだ。 CやJavaなどのようにリスト要素の数(サイズ)を指定する必要もなく、いつでもサイズを変更できる。 しかも、リスト内には(整数や浮動小数点や文字列など一つ定めた(同じタイプの要素を並べる必要はなく、任意のオブジェクトを取ることが可能である。
リストは 角括弧 [ ] 内に、リスト要素をカンマ(,)で区切って並べる。
>>> a = [24, "Alice", 3.14, True, "B", 0xaff0] >>> a [24, 'Alice', 3.14, True, 'B', 45040] >>> len(a) 6 >>> a[0] 24 a[4] 'B' >>> a[5] 45040 >>> a[len(a) - 1] 45040 >>> a[6] >>> Traceback (most recent call last): File "", line 1, in IndexError: list index out of range
上のPython shellの結果からわかるように、リスト変数 a を作成するには角括弧 [ と ] をカンマで区切った要素を挟む。 リストの長さは関数 len で取得できる(上の例では len(a) の結果は6)。
リスト要素へのアクセス(取得)には要素位置(インデックス)を a[位置] の用に指定るする。 ただし、リスト先頭の要素位置は 0 から始まる(多くのプログラム言語も同様)。 したがって、リストの末尾要素は a[len(a) - 1] である。 リスト要素位置の範囲を逸脱すると、最後の例のように IndexError: list index out of range のエラーとなる。
リストを空リストで作成してもよい。 あとからいくらでも要素を追加できる。
>>> a = []
リストのメソッド
リスト変数名を alist とする。 文字列へメソッドはPython入門(3) 文字列で見たように、元の文字列内容を変化させない。 一方以下で見るように、リストへのメソッドはリスト内容を変化させてしまう。 このようなリストの性質を変更可能 (mutability)という。
method名 | 使用例 | 意味 |
---|---|---|
append | alist.append(item) | リストの末尾に要素 item を追加する |
insert | alist.insert(k, item) | リストのk番目位置に末尾に要素 item を挿入する |
extend | alist.extend(blist) | リスト alist に別に用意したリスト blist の末尾に追加する。 |
pop | alist.pop() | リスト末尾の要素を返し、残りのリストを返す |
pop | alist.pop(k) | リストの番目末尾の要素を返し、残りのリストを返す |
remove | alist.remove(item) | リスト内で最初に位置する要素 item を削除する。 |
reverse | alist.reverse() | リスト要素の並びを逆にする |
index | alist.index(item) | リスト内で item が最初に登場する位置を返す。リストに itemがなければエラー |
count | alist.count(item) | リスト内にある item の数を返す。リストに itemがなければ 0を返す。 |
sort | alist.sort() | リスト内の要素を並べ替える。 sort(key=None, reverse=None)とオプション key と reverse をもつ。 オプションを省略したときはデフォルト値 None が指定されたとする。 reverse=Trueとすると降順並べ替えする。 key は、比較を行う前にリストの各要素に対して呼び出される関数を指定できる。 |
文字列操作とことなり、 リスト内の要素を別の要素に置き換えるメソッド replace は用意されていない。 リスト要素の置き換えは
リストのメソッドではないが、しばはリスト要素の削除に使われる del文 がある。
文名 | 使用例 | 意味 |
---|---|---|
del | del alist[k] | 関数として del(alist[k]) と書くことも多い。リスト位置のk番目の要素を削除し、リスト内容を変更する。 |
リスとの並べ替え(sort)では、メソッド .sort() 以外に、次の関数 sorted がよく使われる。
関数名 | 使用例 | 意味 |
---|---|---|
sorted | sorted(slist) | ソートされたリストを返す。元のリストは変更されない。 sorted(alist, reverse=True) パラメータとすると降順となる。 key パラメータも指定でき、比較を行う前にリストの各要素に対して呼び出される関数を指定できる。 |
リストに要素を追加する
Pythonでは、リストに新たに要素を追加する3つのメソッド append、insert、extend がある。
append(要素) はリストの末尾に1つ要素を追加する。 次は、リスト a の末尾に文字列要素 "new" を追加した様子である。 メソッド append によってリスト内容も更新されていることに注意する。
>>> a = [24, "Alice"] >>> a.append("new") >>> a >>> [24, 'Alice', 'new']
insert(場所, 要素) は指定した要素場所に要素を追加する。 次は、リスト a の要素位置 1 に文字列要素 "new" を追加した様子である。 メソッド insert によってリスト内容も更新されていることに注意する。 insert 前のリスト a の a[1] は文字列 "Alice" であるが、要素位置 1 にinsert 後には a[1] は "new" となり、追加前の要素位置が1つづつ後ろにずれている。
>>> a = [24, "Alice"] >>> a[1] 'Alice' >>> a.insert(1, "new") >>> a[1] 'new' >>> a [24, 'new', 'Alice']
extend は、現在のリスト末尾に別のリストのすべての要素を追加する(append, insert 共に追加する要素は1つずつだ)。 次は、リスト a の末尾に別のリスト b の全ての要素を追加した様子である。 メソッド extend によってリスト内容も更新されていることに注意する。
>>> a = [24, "Alice"] >>> b = ["Bob", 32, 1.414] >>> a.extend(b) >>> a [24, 'Alice', 'Bob', 32, 1.414] >>> b ['Bob', 32, 1.414]
次のスクリプト list_add.py を見てみよう。 キーボードから文字列 "e" または "E" が入力されないかぎり、入力文字列を appenし続ける。 break は、ある条件が発生した場合に while文またはfor文のループから脱出する。
#!/usr/bin/env python # -*- coding: utf-8 -*- # a を空リストとして初期化する a = [] while True: st = raw_input("input string(e/E for termination) :") if not(st == "e" or st == "E"): a.append(st) else: break print "This is out of for block" print "list a ", a
実行結果は次のようになる。
input string(e/E for termination) :apple input string(e/E for termination) :orange input string(e/E for termination) :lemon input string(e/E for termination) :e This is out of for block You make a list ['apple', 'orange', 'lemon']
#!/usr/bin/env python # -*- coding: utf-8 -*- # a を空リストとして初期化する a = [] st = "" while not(st == "e" or st == "E"): a.append(st) print "list a ", a st = raw_input("input string(e/E for termination) :") print "This is out of for block" print "You make a list ", a
iterable要素をカウンタ値とするfor文
iterable要素をカウンタ値とするで説明したように、 Pythonの繰り返し for A in B: であらわれる B は繰り返し可能オブジェクト(iterable)である。 iterableなオブジェクトとは要素が並んでいるデータで、順番に次の要素が取り出されるというようになっている。
たとえば、次のようにして、for文のカウンタ変数 item が取る値をリスト a 内の要素にすることができる。
for item in a: 文1 ... 文n

リスト内容を書き出す
まず、次の演習を行ってみよう。
a = [[1,2], 3, 'Apple', [4,[5,6]], False] for i in a: print iを実行してみなさい。
リスト a が既にあってその要素にアクセス(表示)するには、上の素朴な演習以外にも、次のようにリスト位置からなるリストを range(len(a)) で作成して、リスト内の要素位置(index)を指定しながら書き出すことができる。
# リスト a は既に定義されている for index in range(len(a)): print index, a[index])
関数 enumerate によって、リスト a を引数として enumerate(a) は インデクス付けされたリスト要素の列(リスト) [(0, a[0]), (1, a[1]), ...] を返す。 したがって、上と同じ結果を得るには次のように書けばよい。
# リスト a は既に定義されている for (index, item) in enumerate(a): print index, item

文字列の文字をカウンタ値とするfor文

For文のカウンタ値としてリスト要素を取り得るのと同様に、For文で文字列内の文字をカウンタ値とすることができる。
#!/usr/bin/env python # -*- coding: utf-8 -*- st = "Hello, World" for ch in st: print chこのスクリプトの実行結果は次のようになる。
H e l l o , W o r l d
#!/usr/bin/env python # -*- coding: utf-8 -*- word_list =["Apple", "Orange", "Apricot"] char_list = [] for word in word_list: for char in word: char_list.append(char) print char_list
リスとの並べ替え

次の例は、数値文字列を要素とするリストにメソッド .sort を適用した例である。
>>> a = ['1','5', '11','44','8'] >>> a ['1', '11', '44', '5', '8'] >>> a = ['1','5', '11','44','8'] >>> a.sort(key = int) >>> a ['1', '5', '8', '11', '44'] >>> a = ['1','5', '11','44','8'] >>> a.sort(key = int, reverse = True) >>> a ['44', '11', '8', '5', '1'] >>> sorted(a, key = int) ['1', '5', '8', '11', '44']
リスト内包表記

Pythonでは、新たなリストを生成するリスト内包表記(list comprehension)という強力な手段を備えている。 以下の例のように、リストの内包表記は、式に続いて for文、その後ろに続くゼロ個以上の for文または if文からなる。
x を range(10) が与えるリスト [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] の各要素として、それらを2乗して得られるリストを生成するのは、次のようにして式を x * x とする内包表記で実現できる。
>>> [x * x for x in range(10)] [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
range(10) が与えるリスト [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] の各要素が 2で割り切れない(余りが0でない) 要素について2乗したリストはリスト内包表記で次にように書ける。
>>> [x * x for x in range(10) if x % 2 != 0] [1, 9, 25, 49, 81]
文字列がiterableであることを使うと、次のような選択的操作によって「複雑な」処理を一気に書くことができる。
>>> [ch.upper() for ch in "World Wide Web" if ch not in "internet"] ['W', 'O', 'L', 'D', ' ', 'W', 'D', ' ', 'W', 'B']
文字列(文字)リストを空白なく連接(concatenate)するには、'連結文字'.join(リスト) として次のように書ける。
"".join([ch.upper() for ch in "World Wide Web" if ch not in "internet"])
リスト内包表記でforを入れ子にする
上のスクリプト for_string_char.py はリスト内包表記を使うと次のように書ける。
>>> [ch for word in ["Apple", "Orange", "Apricot"] for ch in word ]
リスト要素の置き換え
リスト要素の置き換えを考えてみよう。 Pythonでは、リスト mylist の要素 item を別の要素 other に置き換えるメソッド mylist.replace(item, other) は用意されていない。
しかしながら、リスト要素が文字(列)の場合には、文字列操作においては、文字列 mystring の文字列 before を検索し、文字列 after にすべて置き換えるメソッド mystring.replace(before, after) を使うことができる。
ここでは、以下、リストは文字列からなると仮定する。
リスト mylist の要素がすべて文字(列)の場合、文字列の置き換えメソッド replace を使って
mylist = [word.replace('before', 'other') for word in mylist]として、要素の(にすくまれる)文字(列) 'before' をすべて文字(列) 'other' に置き換えることができる。

では、リスト要素に、文字(列)item1 と item2 が含まれているとき、item1 と item2 とを入れ替え(swap)する、つまり、item1 のある場所を item2 に入れ替え、『同時に』 item2 がある場所を item1 にに入れ替えるにはどうすればよいだろうか。
リスト ['a', 'b', 'a', 'b', 'c', 'c', 'a'] において、要素 'a' と 'b' とをswap a $\rightleftarrows$ b して ['b', 'a', 'b', 'a', 'c', 'c', 'b'] とするのである。
(ヒント):item1 をリスト要素には決して含まれないような文字列 never(を考える) に置き換えたリストを作成し、次いで、item2 を item1 に置き換えたリストを作成し、 最後に、そのリストの never を item2 に置き換えたリストを返す、というように置き換えを2段階経る必要がある。
リストのリスト
リストの要素はリストでもよい。 次のような例を考える。
>>> a = [[2, 3, 4], [5, 6, 7], [8, 9, 10], [11, 12, 13]] >>> a[0] [2, 3, 4] >>> a[3] >>> [11, 12, 13] >>> a[3][2] 13
この例では、 aは4行3列の行列(2次元配列)である。 最後の例に注意してほしい。 リスト a の3番目(のリスト)要素の2番目にアクセスするためには a[3][2] と表記すのであって、a[3,2] とは書けないということである
Pythonには、規模な多次元配列や行列のサポート、これらを操作するための高水準の拡張数学関数ライブラリ NumPyがある。 行列計算を行う場合には大変便利で、Pythonで科学計算をおこなうためにはSciPyと並んで必須モジュールである。
自分のPython環境でNumPyが使えるかは次を実行してみれば分かる。
import numpy
次の3行3列の行列を入力してみる。
>>> mat = [ [1,2,3], [4,5,6], [7,8,9], ]
行と列を入れ換えて転置行列を出力したいときには、次のようなリスト内包表記が使える。
>>> print [[row[i] for row in mat] for i in [0, 1, 2]] [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
この操作は、次の手続きに相当する。
for i in [0, 1, 2]: for row in mat: print row[i], print
List構造のフラット化
リストの要素がリストであるようなリスト [[2, 3, 4], [5, 6, 7], [8, 9, 10], [11, 12, 13]] で、それを構成しているアトムを要素とするリストとして並べることをフラット化(flatten)という。 [['a', 'b'], ['a']] ならどうだだろうか。
この例では、つぎのようにフラット化されるようにしたい。
[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] ['a', 'b', 'a']
深さが異なるリストのフラット化

リスト [[1, 3], [[5]], [[7], 9]] はその要素が3つのリストからなり、リストは各リスト要素は再びリストからなっている。 これ完全にをフラット化できれば [1, 3, 5, 7, 9]] となる。
また、リスト [1, [2,3], [[4, [5,6]], 7]] は3つの要素をもち、2つ目と3つ目の要素はリストで、3つ目のリストにおいて、その最初の要素はリスト [4,[5,6]]で、さらのその2つめの要素もリスト [5,6] である。 結局、与えられたリストは最大の深さ(depth)3を持つ。 これ完全にをフラット化できれば [1, 2, 3, 4, 5, 6, 7] となる。
2つの検索文字列を「同時に置き換える」で考えた文字列の置き換え代入操作をリストで考えてみよう。 要素文字 'a'と 'b' だけからなるリストを考え、'a をリスト ['a', 'b'] に、'b' をリスト ['a'] に置き換える操作 $r$ を考える。 \[ r: \begin{cases} \text{'a'}\rightarrow \text{['a', 'b']},\\ \text{'b'}\rightarrow \text{['a']} \end{cases} \]
この操作によって、リスト ['a'] に操作 $r$ を繰り返し適用することによって次のようなリストを得ることができる。
\begin{align*} r\text{['a']} &\rightarrow\text{['a', 'b']}\\ r^2\text{['a']} &\rightarrow \text{['a', 'b', 'a']},\\ r^3\text{['a']} &\rightarrow \text{['a', 'b', 'a', 'a', 'b']}\\ r^4\text{['a']} &\rightarrow \text{['a', 'b', 'a', 'a', 'b', 'a', 'b', 'a']},\\ \dots & \end{align*}結果を文字列として得たいときは。文字列操作メソッド join を使って次のようにすればよい。
>>> "".join(['a', 'b', 'a', 'a', 'b', 'a', 'b', 'a']) 'abaababa'