skip to content
barorin&

Pythonのリスト操作まとめ|結合・分割・重複除去・内包表記

/ 8 min read

Table of Contents

はじめに

リスト操作は毎回同じことを調べ直しがちな領域です。この記事では、実際に使う頻度の高いものをまとめました。書き方が複数あるものは、どれを選ぶべきかまで書いています。

リストを文字列に変換する

join() を使います。呼び出すのは「区切り文字のほう」である点に注意してください。

lst = ["a", "b", "c"]
",".join(lst)
# 'a,b,c'
"\n".join(lst)
# a
# b
# c

リストにリストをつなげる

extend() を使うのがもっとも素直です。

lst = ["I", "my", "me"]
addlist = ["one", "two", "three"]
lst.extend(addlist)
# ['I', 'my', 'me', 'one', 'two', 'three']

+= でも同じ結果になります。

lst += addlist

新しいリストを作りたい場合は + を使います。

new_lst = lst + addlist # 元のlstは変わらない

入れ子になったリストを平坦にする

書き方は2つあります。どちらも結果は同じです。

nested = [[0, 1], [2, 3], [4, 5, 6]]
# 1. リスト内包表記
[i for lst in nested for i in lst]
# [0, 1, 2, 3, 4, 5, 6]
# 2. itertools を使う
import itertools
list(itertools.chain.from_iterable(nested))
# [0, 1, 2, 3, 4, 5, 6]

内包表記は追加のimportが要らず、itertools のほうは要素数が多いときにわずかに速くなります。普段は内包表記で十分です。

内包表記の for の順序は、外側のループから先に書きます。通常のfor文を左から右へ並べたものと同じ順です。

# これと同じ意味
result = []
for lst in nested:
for i in lst:
result.append(i)

重複を除いて順序を保つ

set() は重複を消しますが、順序が保証されません。順序を保ったまま重複を除くなら dict.fromkeys() を使います。

lst = ["john", "alice", "joe", "john"]
list(dict.fromkeys(lst))
# ['john', 'alice', 'joe']

Python 3.7以降、辞書はキーの挿入順を保持することが言語仕様で保証されているため、この書き方が確実です。

空の要素を削除する

リスト内包表記で条件を指定します。

lst = ["", "a", "b", "", "", "c", ""]
[x for x in lst if x != ""]
# ['a', 'b', 'c']

if x と書くと、空文字だけでなく None0、空リストなど偽と評価されるすべてが除かれます。

lst = ["", "a", None, "b", 0, "c"]
[x for x in lst if x != ""] # ['a', None, 'b', 0, 'c']
[x for x in lst if x] # ['a', 'b', 'c']

金額の 0 を残したい場合に if x を使うと消えてしまうので、何を落としたいのかを意識して選んでください。

リストを任意のサイズに分割する

n個ずつのまとまりに切り分けます。

l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
n = 3
[l[idx:idx + n] for idx in range(0, len(l), n)]
# [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]

range(0, len(l), n) で開始位置を n 個飛ばしに作り、そこから n 個ずつスライスする、という仕組みです。最後の余りは自動的に短いまとまりになります。

API へのリクエストを一定件数ずつに区切って送るときなどに使えます。

if を混ぜたリスト内包表記

条件に合う要素だけを集めます。

columns = ["I am Sam", "She is Erica", "He is Eric"]
[c for c in columns if "Sam" in c]
# ['I am Sam']

通常のfor文で書くとこうなります。

lst = []
for c in columns:
if "Sam" in c:
lst.append(c)

条件によって値を変えたい場合は、iffor の前に置く三項演算子の形になります。位置が違うので注意してください。

# 絞り込み: if は後ろ
[c for c in columns if "Sam" in c]
# 値の変換: if〜else は前
["該当" if "Sam" in c else "対象外" for c in columns]
# ['該当', '対象外', '対象外']

スライスのカンマ(numpy)

Pythonの標準リストは1次元のスライスしかできませんが、numpyの配列はカンマ区切りで次元ごとに指定できます。

import numpy as np
a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
a[:, 0] # [1 4 7] ← 全行の0番目
a[:1, 0] # [1] ← 0行目までの0番目
a[:2, 1] # [2 5] ← 0〜1行目の1番目
a[:3, 1] # [2 5 8]

カンマの前が行、後ろが列です。: だけを書くと「その次元すべて」を意味します。

おわりに

リスト操作は書き方が複数あるものが多く、どれも動いてしまうため、なんとなく最初に見つけた書き方を使い続けがちです。件数が増えたときに効いてくるのは重複除去のような処理なので、そこだけは書き方を選んでおくと後で困りません。

この記事を書いた人

barorinのプロフィール画像

barorin公認会計士

会計とITの二足のわらじで働く公認会計士です。Pythonを中心に、会計・監査の実務で実際に使っているコードや、Ubuntu・Raspberry Piの設定メモを書いています。