#!/usr/bin/env python # coding: utf-8 # (ch:list)= # # リスト # ## 基本 # [リスト](https://docs.python.org/ja/3/library/stdtypes.html?highlight=list#sequence-types-list-tuple-range)は複数の値・オブジェクトをまとめる。要素を`,`で区切って並べ、全体を`[` `]`で囲んで作成する。 # In[1]: a = [0, 1, 4, 9, 16, 25, 36, 49] # In[2]: a # In[3]: type(a) # 先頭要素のインデックス番号は0。 # In[4]: a[0] # In[5]: a[1] # リストの要素数は[len](https://docs.python.org/ja/3/library/functions.html#len)関数で取得する。 # In[6]: len(a) # 要素の範囲を超えてリストにアクセスするとエラーになる。 # In[7]: a[8] # リストの最後の要素のインデックス番号は「要素数 - 1」。 # In[8]: a[len(a)-1] # リストの要素を末尾からアクセスするため、負のインデックス番号を用いることができる。 # In[9]: a[-1] # In[10]: a[-2] # 空のリストは`[]`か[list](https://docs.python.org/ja/3/library/stdtypes.html#list)関数で作成する。 # In[11]: a = [] a # In[12]: a = list() a # ## スライス # `a[start:end:step]`という形式で、リストの要素の部分列を抽出できる(「スライス」と呼ばれる)。 # + `start`: 抽出を開始する要素のインデックス番号。省略された場合は`0`となる。 # + `end`: 抽出を終了する要素のインデックス番号(ただし、`a[end]`の要素は含まれない)。省略された場合はリストの要素数となる。 # + `step`: 要素を抽出する間隔。省略された場合は`1`である。 # In[13]: a = [0, 1, 4, 9, 16, 25, 36, 49] # 開始位置と終了位置を指定したスライス。 # In[14]: a[2:5] # In[15]: a[0:3] # 開始位置を省略したスライス。 # In[16]: a[:3] # 終了位置を省略したスライス。 # In[17]: a[5:] # 負のインデックス番号を用いてもよい。 # In[18]: a[-3:] # 要素を取り出す間隔を指定したスライス。 # In[19]: a[1::2] # 間隔に`-1`を指定して、逆順に要素を取り出すスライス(`a[5]`, `a[4]`, `a[3]`が取り出される)。 # In[20]: a[5:2:-1] # 開始位置と終了位置を省略し、全ての要素を逆順に取り出すスライス。 # In[21]: a[::-1] # ## リストの要素に対する繰り返し # In[22]: a = [0, 1, 4, 9, 16, 25, 36, 49] # リストの要素に先頭から繰り返しアクセスする。 # In[23]: for x in a: print(x) # リストの要素に先頭から繰り返しアクセスすると同時に、各要素のインデックス番号を得る。 # In[24]: for i, x in enumerate(a): print(i, x, a[i]) # リストの要素に末尾から繰り返しアクセスする。 # In[25]: for x in reversed(a): print(x) # ## リストの要素に対する操作 # In[26]: wd = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday'] wd # リスト内の要素を変更する。 # In[27]: wd[1] = 'tue' wd # 末尾に要素を追加する。 # In[28]: wd = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday'] wd.append('saturday') # In[29]: wd # 指定した要素を削除する。 # In[30]: del wd[5] # In[31]: wd # リストを連結して、新しいリストを作成する。 # In[32]: d = wd + ['saturday', 'sunday'] # In[33]: d # リストをスタックと見なしてpop操作をすると、末尾の要素が取り出され、同時に末尾の要素がリストから削除される。 # In[34]: d.pop() # In[35]: d # push操作に相当するものはappend関数である。 # In[36]: d.append('sun') d # ## 要素の並び替え # # 要素を降順に並べたリストを新たに作成する(この場合は辞書順に並ぶ)。 # In[37]: sorted(d) # 元のリスト(`d`)は変更されていない。 # In[38]: d # 引数reverseを`True`にセットすると、要素を昇順に並べたリストを新たに作成できる(この場合は辞書の逆順に並ぶ)。 # In[39]: sorted(d, reverse=True) # 並び替えにおける要素の並び順は要素に対する比較演算子`<`の結果に基づく。例えば、`'saturday' < 'sun'`が成り立つので、`'saturday'`が`'sun'`の前に並ぶ。要素を比較するときの基準を変更したいときは、引数keyを用いる。以下の例では、要素の長さ(文字数)を取得する無名関数(lambda)を定義し、それをkey引数に渡すことで、文字数の少ない要素の順に並び替えている。 # In[40]: sorted(d, key=lambda x: len(x)) # 引数reverseと併用して、文字数の多い要素の順に並び替える例である。 # In[41]: sorted(d, key=lambda x: len(x), reverse=True) # 要素を降順に並び替える。今回は、リスト`d`の要素そのものが並び替えられる。 # In[42]: d.sort() d # 要素を昇順に並び替える。 # In[43]: d.sort(reverse=True) d # 引数keyに関数を指定して、要素の並べ方を変更できる。 # In[44]: d.sort(key=lambda x: len(x)) d # ## 要素の所属検査 # # ある要素がリストに含まれるかを調べる。 # In[45]: 'sun' in d # ある要素がリストに含まれないかを調べる。 # In[46]: 'sun' not in d # ## リストと参照 # ### 参照の代入 # リスト`x`を作成する。 # In[47]: x = ['mon', 'tue', 'wed', 'thu', 'fri'] x # 変数`y`を作成し、リストである`x`を代入する。 # In[48]: y = x y # リスト`y`に要素を追加してみる。 # In[49]: y.append('sat') y.append('sun') y # (予想に反し)リスト`x`の要素も変更されている(`'sat'`と`'sun'`が追加されている)。 # In[50]: x # これは、代入文`y = x`が「変数`y`を定義し、変数`y`の参照先を変数`x`の参照先と一致させる」という動作を行うからである。元々、変数`x`はリストオブジェクトを参照していた(関連付けられていた)ので、そのリスト・オブジェクトに複数の変数`x`と`y`を経由してアクセスできるようになった。ひとつのオブジェクトの実体を複数の変数`x`と`y`が参照している状況であるので、いずれの変数を経由してもオブジェクトの内容を変更できるし、いずれの変数を評価しても同じ結果が得られる。 # ### リストのコピー # # 先ほどと同様に、リスト`x`を作成する。 # In[51]: x = ['mon', 'tue', 'wed', 'thu', 'fri'] x # 変数`y`を作成し、リストである`x`の全体のスライス`x[:]`を代入する。このとき、`x`のリスト・オブジェクトのコピーが作成され、変数`y`はコピーを参照することになる。 # In[52]: y = x[:] y # 先ほどと同様に、リスト`y`に要素を追加してみる。 # In[53]: y.append('sat') y.append('sun') # In[54]: y # 今回は、リスト`x`の要素は変更されない。これは、変数`x`と`y`が、それぞれ別のリスト・オブジェクトを参照しているからである。 # In[55]: x # ## リストと関数の引数 # 引数で与えられたリストの末尾に`'END'`を追加する関数append_endを定義する。 # In[56]: def append_end(s): s.append('END') # 以下のリスト`x`を引数として、関数append_endを呼び出す。 # In[57]: x = ['one', 'two'] x # In[58]: append_end(x) # すると、呼び出し元の変数である`x`の内容が変化する。 # In[59]: x # 数値や文字列を引数として関数に渡す場合と異なり、リストを引数として関数に渡すと、その関数内でそのリストに対する変更は、関数の呼び出し元にも波及する。 # ## リストの様々な作成方法 # [range](https://docs.python.org/ja/3/library/stdtypes.html#range)関数が表す範囲に対応するリストを作成するには、[list](https://docs.python.org/ja/3/library/stdtypes.html#list)関数を用いる。 # In[60]: a = list(range(10)) a # In[61]: a = list(range(1, 10, 2)) a # リストの要素はデータ型が異なってもよい。 # In[62]: b = [1, 'one', 'first'] # In[63]: b[0] # In[64]: b[1] # (0を含む)自然数のリストを[range](https://docs.python.org/ja/3/library/functions.html#func-range)関数で作成する。 # In[65]: a = list(range(10)) a # ### リストの内包表記 # 空のリストを作成する。 # In[66]: a2 = [] a2 # 空のリスト(`a2`)に要素を追加する # In[67]: for i in range(10): a2.append(i * 2) a2 # これは2の段の掛け算の結果を表している。 # In[68]: a2[7] # 上記の処理はリストの内包表記を使って簡潔に書ける。ソースコードを左から"list of i times two for all i in the range of ten"のように英語読みをすると解釈しやすい。 # In[69]: a2n = [i * 2 for i in range(10)] a2n # In[70]: a2n[7] # 3の段の掛け算も内包表記を使って簡潔に書ける。 # In[71]: [i * 3 for i in range(10)] # 内包表記を入れ子にして、掛け算表を2次元配列(リスト)として作成する。 # In[72]: m = [[i * j for i in range(10)] for j in range(10)] # In[73]: m # In[74]: m[2] # In[75]: m[2][3] # ### 2次元配列作成時の注意 # `*`演算子を使うと、指定した値で初期化しながら、指定した要素数のリストを作ることができる。 # In[76]: a = [0] * 10 a # これを拡張して、2次元配列を作ることもできるが、これは避けるべきである。 # In[77]: a = [[0] * 10] * 10 a # 一見すると2次元配列が作成されたように見えるが、思わぬ落とし穴がある。以下のコードである要素を変更したつもりが、列全体の値が変更されてしまう。 # In[78]: a[3][5] = 2 a # これは、`[0] * 10`で1次元のリスト・オブジェクトが一つだけ作成され、その唯一のオブジェクトへの参照が全ての`a[.]`にセットされただけであるからである。 # 指定したサイズのリストを作成するときに、内包表記を使うこともできる。 # In[79]: b = [0 for i in range(10)] b # これを拡張して、2次元配列を作ることができる。 # In[80]: b = [[0 for i in range(10)] for j in range(10)] b # こちらは、我々が通常期待する2次元配列として振る舞う。 # In[81]: b[3][5] = 2 b # --- # # [Python早見帳](https://chokkan.github.io/python/) © Copyright 2020-2022 by [岡崎 直観 (Naoaki Okazaki)](https://www.chokkan.org/). この作品はクリエイティブ・コモンズ 表示 - 非営利 - 改変禁止 4.0 国際 ライセンスの下に提供されています。クリエイティブ・コモンズ・ライセンス