Python 便利なリスト演算まとめ

f:id:monozukuri-bu:20190816145258j:plain

最近やっと暑くなってきたので海に行きたいhashiです。
現在、Python3エンジニア認定基礎試験の勉強に励んでいます。
資格勉強のためチュートリアルを見返すとリストへの操作には、融通の利くいろいろな演算があると気づかされました。
分かりにくい所もあるので、実行結果とともにまとめてみます。

そもそもリストとは

ドキュメントによると、

リストはミュータブルなシーケンスで、一般的に同種の項目の集まりを格納するために使われます (厳密な類似の度合いはアプリケーションによって異なる場合があります)。

「同種の項目の集まりを格納する」はわかりやすいですが、「ミュータブル」とは……?
用語集に頼ることにします。

docs.python.org

  • mutable(ミュータブル)
    ミュータブルなオブジェクトは、 id() を変えることなく値を変更できます。イミュータブル (immutable) も参照してください。

うーん……。イミュータブルの解説を見てみます。

  • immutable(イミュータブル)
    固定の値を持ったオブジェクトです。イミュータブルなオブジェクトには、数値、文字列、およびタプルなどがあります。これらのオブジェクトは値を変えられません。別の値を記憶させる際には、新たなオブジェクトを作成しなければなりません。イミュータブルなオブジェクトは、固定のハッシュ値が必要となる状況で重要な役割を果たします。辞書のキーがその例です。

数値aに対してa = a + 1という操作をするときには、aという箱の中身を変えているわけではなく、
新しいオブジェクトにaという名前を付けているという感じでしょうか。
それに対してリストは外観を変えずに箱の中身(が見ているオブジェクト)を変えられるという理解でよさそうです。

演算

特定の値がリストに含まれているかの判定

x in s
リストsの要素の中にxと等しいものがあればTrue、なければFalseを返す。

x not in s
リストsの要素の中にxと等しいものがなければTrue、あればFalseを返す。

わざわざfor文を回すことなく要素の存在を確認できるのは、コードの分量も減りうれしいですね。

sample_list = [1, 2, 3, 100, 1, 7, 9]
print("sample_list:" + str(sample_list))

"""
もうこんな行数いらない!
for i in sample_list:
    if i == 0:
        print(True)
        break
else:
    print(False)
"""

# 特定の値が含まれているかの判定
print("0 in sample_list")
print(0 in sample_list)

# 特定の値が含まれていないかの判定
print("0 not in sample_list")
print(0 not in sample_list)

実行結果

sample_list:[1, 2, 3, 100, 1, 7, 9]
0 in sample_list
False
0 not in sample_list
True

結合

s + t
リストsの後ろにリストtが続くリストを返す。

s*x
リストsをx(整数)個つなげたリストを返す。x<=0の時は空のリストを返す。

リスト同士の足し算、リストと整数の掛け算によってリストの結合が可能です。

sample_list = [1, 2, 3, 100, 1, 7, 9]
print("sample_list:" + str(sample_list))

print(sample_list + [7])    # 2つのリストの結合
print(sample_list * 3)       # 同じリストを3つ結合
print(sample_list * (0))    # 同じリストを0つ結合=空のリスト
print(sample_list * (-6))  # 0未満の値は0と扱われる
print(sample_list)  # 元のリストに影響はない

実行結果

sample_list:[1, 2, 3, 100, 1, 7, 9]
[1, 2, 3, 100, 1, 7, 9, 7]
[1, 2, 3, 100, 1, 7, 9, 1, 2, 3, 100, 1, 7, 9, 1, 2, 3, 100, 1, 7, 9]
[]
[]
[1, 2, 3, 100, 1, 7, 9]

要素の抜き出し

s[i]
i番目の要素を抜き出す。

s[i:j]
i番目からj-1番目まで抜き出す。

s[i:j:k]
i番目からj-1番目までの範囲の、k個ごとに抜き出す。

sample_list = [1, 2, 3, 100, 1, 7, 9]
print("sample_list:" + str(sample_list))
i, j, k = 1, 7, 2
print(sample_list[i])  # i番目の値を抜き出す
print(sample_list[i:j])  # i番目からj-1番目までのリストを抜き出す
print(sample_list[i:j:k])  # i+nk (i<=i+nk<j, nは非負の整数)番目の値のリストを抜き出す

実行結果

sample_list:[1, 2, 3, 100, 1, 7, 9]
2
[2, 3, 100, 1, 7, 9]
[2, 100, 7]

また、i,jに負数を指定するとリストの後ろからの距離でインデックスを指定できたり、
スライスのi,jを省略しても良きに計らってくれるのが便利です。

sample_list = [1, 2, 3, 100, 1, 7, 9, 10]
print("sample_list:" + str(sample_list))
i, j, k = 1, 7, 2

print(sample_list[-i])  # (最後尾を1として)最後からi番目の値を抜き出す
print(sample_list[i:])  # i番目から(リストのサイズ-1番目まで)のリストを抜き出す
print(sample_list[-5:])  # リストの後ろから5つの要素を抜き出す
print(sample_list[:j])  # (0番目から)j-1番目までのリストを抜き出す
print(sample_list[:-5])  # (0番目から)リストの後ろから5つを除いた要素を抜き出す
print(sample_list[::-1])  # (0番目からリストのサイズ-1番目までの)リストを-1刻みで抜き取ることで得られるリストを抜き出す

実行結果

sample_list:[1, 2, 3, 100, 1, 7, 9, 10]
10
[2, 3, 100, 1, 7, 9, 10]
[100, 1, 7, 9, 10]
[1, 2, 3, 100, 1, 7, 9]
[1, 2, 3]
[10, 9, 7, 1, 100, 3, 2, 1]

print(sample_list[::-1])はリストを逆順で表示するという意味になるのでlist(reversed(sample_list))とも書けますが、
スライスを使ったほうが簡単ですね。

リストの編集

s[i]=x
i番目の要素をxに入れ替える。

s[i:j]=l
i番目からj-1番目までをリストlに入れ替える。

s.append=x
リストの最後尾にxを追加する。

s.reverse()
リストの中身を逆順にする

ここまでの演算では元のリストの中身に影響がありませんでしたが、これ以降はリストの中身を編集します。

sample_list = [1, 2, 3, 100, 1, 7, 9]
print("sample_list:" + str(sample_list))
sample_list[0] = 2  # 指定したインデックスの要素を変える
print(sample_list)

sample_list = [1, 2, 3, 100, 1, 7, 9]
sample_list[1:4] = [0, 0, 0, 0, 0]  # 指定した範囲を入れ替える(長さは同じでなくてもよい)
print(sample_list)

sample_list = [1, 2, 3, 100, 1, 7, 9]
sample_list.append(9)  # 最後尾に要素を追加
print(sample_list)  # 最後尾に9が追加されている

sample_list = [1, 2, 3, 100, 1, 7, 9]
sample_list.reverse()  # 逆順にする
print(sample_list)

実行結果

sample_list:[1, 2, 3, 100, 1, 7, 9]
[2, 2, 3, 100, 1, 7, 9]
[1, 0, 0, 0, 0, 0, 1, 7, 9]
[1, 2, 3, 100, 1, 7, 9, 9]
[9, 7, 1, 100, 3, 2, 1]

リストのソート

s.sort()
リストsを昇順でソートする(実行前後でsの中身が変わる)
引数にkey=...,reverse=...をとることができ、ソートの条件を指定できる

 - key=(1引数をとる関数)
 リストの要素を関数に渡したときの戻り値を使ってソートを行うようにする

 - reverse=(真偽値)
Trueならば降順、Falseなら昇順にソートを行う

keyの指定方法がちょっとわかりにくいですが、リスト中の要素でソートしたい時などに便利です。
また、ソート前のリストを保持しておきたい場合はsorted()を使うと元のリストをいじらずにソート済みリストを取得できます。

sample_list = [1, 2, -3, 100, -1, 7, -9]
print("sample_list:" + str(sample_list))

sample_list.sort()  # ソート(デフォルトは昇順)
print(sample_list)

sample_list.sort(reverse=True)  # 逆順ソート
print(sample_list)

sample_list.sort(key=abs)  # 値の絶対値でソート
print(sample_list)

listlist = [[100, 1], [0, 3], [9, 2]]
print("listlist:"+str(listlist))

listlist.sort(key=lambda x: x[1])  # リストの1番目の値をソートに使う
print(listlist)

実行結果

sample_list:[1, 2, -3, 100, -1, 7, -9]
[-9, -3, -1, 1, 2, 7, 100]
[100, 7, 2, 1, -1, -3, -9]
[1, -1, 2, -3, 7, -9, 100]
listlist:[[100, 1], [0, 3], [9, 2]]
[[100, 1], [9, 2], [0, 3]]

まとめ

Python3でのリストの仕様や便利なメソッドなどをまとめました。
活用して短く読みやすいコードを書きたいと思います。