Open10

python のリスト操作の軽いまとめ的なやつ

とがとが

python のリストは,四角括弧でくくってカンマ区切りで要素を書く.

a = [50, 80, 10]

要素へのアクセスは C++ と同じ

print(a[0]) # -> 50
print(a[1]) # -> 80
print(a[2]) # -> 10
とがとが

+ で結合できる

print([1, 2, 3] + [4, 5, 6]) # -> [1, 2, 3, 4, 5, 6]

* で繰り返せる

print([1, 2, 3] * 3) # -> [1, 2, 3, 1, 2, 3, 1, 2, 3]

[0, 0, ..., 0]0 が 10 個)みたいなリストを作りたければ [0] * 10 とする.

とがとが

マイナスで後ろから数える

a = [0, 10, 20]
print(a[-1]) # -> 20
print(a[-2]) # -> 10
print(a[-3]) # -> 0
とがとが

a[i:j] は,a[i] から a[j - 1] まで.左を省略すると先頭から,右を省略すると末尾まで

a = [0, 10, 20, 30, 40]

print(a[1:3]) # -> [10, 20]
print(a[1:]) # -> [10, 20, 30, 40]
print(a[:3]) # -> [0, 10, 20]
print(a[:]) # -> [0, 10, 20, 30, 40]
とがとが

for i in a と書いて,a の各要素に対して処理ができる

a = [10, 5, 2, 3]
for i in a:
  print(i + 1)
標準出力
11
6
3
4
とがとが

range(n)n は自然数)は,for で回すとリスト [0, 1, ..., n - 1] のように振る舞う.

for i in range(5):
    print(i)
標準出力
0
1
2
3
4
  • range(n) は 0 以上 n 未満
  • range(a, b)a 以上 b 未満
  • range(a, b, step)a から始めて b の手前まで step ずつ増える(例:range(1, 10, 2) なら [1, 3, 5, 7, 9]range(5, -1, -1) なら [5, 4, 3, 2, 1, 0]
とがとが

リスト内包表記.

a = [2, 5, 1, 3, 4]
b = [i * i for i in a]
print(b) # -> [4, 25, 1, 9, 16]

[i * i for i in a] は「a の各要素 i に対して i * i を計算し,それらを並べたリストを作る」という意味になる.たとえば [i for i in a] だったら a と同じものが出来上がる.

for 文においてリストと同じように振る舞う range(n) は,ここでもリストと同じように振る舞える.

a = [i * 3 for i in range(5)]
print(a) # -> [0, 3, 6, 9, 12]
とがとが

for 文の in の後に書けるものの条件は「先頭から順に走査できること」.[3, 2, 5] のようなリストはもちろん 325 と走査できるし,range(5)01,…,4 と走査できる.このように,先頭から順に走査できるようなものをイテラブルという.

イテラブルは(長さが有限なら)list() を使ってリスト化できる.

a = list(range(5))
print(a) # -> [0, 1, 2, 3, 4]

たとえば range(1000000) と書いても別に 1000000 個の整数分のメモリを食うわけではないけど,list(range(1000000)) とした時点で 1000000 個の整数を並べたリストが作られてメモリが消費される.

for 文で走査するためにはリストっぽい振る舞いが必要だけど,range(n) のように必ずしも全要素分のメモリを消費する必要が無いものもある.そのために「リスト」(全要素をメモリ上に並べる)と「イテラブル」(先頭から走査できる)を区別して,range(n) はイテラブルだがリストではない,という扱いをしている.

とがとが

絶対値をとる abs() という関数がある(たとえば abs(-2) は 2 になる).これをリスト [-2, 5, 1, -4, 3] の全要素に適用して [2, 5, 1, 4, 3] としたい.

このように,リストの各要素に対して一斉に関数を適用するには,map() を使う.ただし,map() はリストだけでなくイテラブルを受け取り,イテラブルを返す.map(関数, イテラブル) と使う.

まずは,イテラブルの代表であるリストを渡して挙動を見る.

a = [-2, 5, 1, -4, 3]
for i in map(abs, a):
    print(i)
標準出力
2
5
1
4
3

map(abs, a) はイテラブルなので,for で走査できている.しかし,このとき全要素に abs() を適用した [2, 5, 1, 4, 3] というリストがメモリ上に作られているわけではない.じゃあ走査するときに何が起こっているかというと,もとのリスト a を見ながら毎回 abs() を適用している.

一方 list() を使えばリストになる.こっちは要素分のメモリを食う.

a = [-2, 5, 1, -4, 3]
b = list(map(abs, a))
print(b) # -> [2, 5, 1, 4, 3]

リストにすると何が変わるかというと,i 番目にアクセスしたり書き換えたりできるようになる.

b[2] = 99
print(b) # -> [2, 5, 99, 4, 3]

イテラブルのままだとこうはできない.

同じことは内包表記でもできる.

a = [-2, 5, 1, -4, 3]
b = [abs(i) for i in a]
print(b) # -> [2, 5, 1, 4, 3]

[abs(i) for i in a] と書くか list(map(abs, a)) と書くか,どっちが良いのかと思って調べたら stackoverflow で侃侃諤諤だった