8.

Python リスト型完全ガイド — 操作/スライス/内包表記/numpy との違い

編集
この記事の要点
  • Python のリスト (list) は可変長・任意型を入れられる動的配列。[1, 2, 3] リテラルで生成
  • インデックス: 0 始まり、負数で末尾から (arr[-1] = 最終要素)。スライス: arr[1:4], arr[::-1] で逆順
  • 主要メソッド: append / extend / insert / pop / remove / sort / reverse / index / count
  • リスト内包表記: [x*2 for x in range(10) if x % 2 == 0] はループ + filter より高速で Pythonic
  • 用途別使い分け: 数値演算なら numpy.array、高速な両端追加なら collections.deque、不変なら tuple

Python リストの基本

Python のlist (リスト) は最もよく使われる組み込みコレクション型です。要素は任意の型を混在できる動的配列で、サイズは自動拡張されます。

# 生成
empty = []
nums = [1, 2, 3, 4, 5]
mixed = [1, "hello", 3.14, True, None]    # 型混在可
nested = [[1, 2], [3, 4]]                  # 二次元

# 範囲生成
zeros = [0] * 10                           # [0, 0, ..., 0] (10 個)
seq = list(range(5))                       # [0, 1, 2, 3, 4]

# 要素数
len(nums)                                  # 5

# アクセス
nums[0]                                    # 1 (先頭)
nums[-1]                                   # 5 (末尾)
nums[-2]                                   # 4 (末尾から 2 番目)
# nums[100] → IndexError

スライス

Python のリストは強力なスライス機能を持ち、部分取得・反転・ステップ指定がワンライナーで書けます。

nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# 基本: arr[start:end] → [start, end)
nums[2:5]          # [2, 3, 4]
nums[:3]           # [0, 1, 2]
nums[5:]           # [5, 6, 7, 8, 9]
nums[:]            # 全要素のコピー

# 負のインデックス
nums[-3:]          # [7, 8, 9] (末尾 3 つ)
nums[:-2]          # [0, 1, 2, 3, 4, 5, 6, 7] (末尾 2 つ除く)

# ステップ
nums[::2]          # [0, 2, 4, 6, 8] (1 つ飛ばし)
nums[1::2]         # [1, 3, 5, 7, 9] (奇数番目)
nums[::-1]         # [9, 8, ..., 0] (反転)
nums[::-2]         # [9, 7, 5, 3, 1]

# スライス代入
nums[2:5] = [20, 30]      # nums = [0, 1, 20, 30, 5, 6, 7, 8, 9]
nums[::2] = [-1, -1, -1, -1, -1]  # 等しい長さなら OK

主要メソッド

メソッド動作計算量
append(x)末尾に追加O(1) 償却
extend(iterable)末尾に複数追加O(k)
insert(i, x)位置 i に挿入O(n)
pop()末尾を取り出すO(1)
pop(i)位置 i を取り出すO(n)
remove(x)最初の x を削除O(n)
clear()全削除O(n)
index(x)x の位置を返すO(n)
count(x)x の出現回数O(n)
sort()in-place ソートO(n log n)
reverse()in-place 反転O(n)
copy()浅いコピーO(n)
arr = [3, 1, 4, 1, 5, 9, 2, 6]

arr.append(7)              # [3, 1, 4, 1, 5, 9, 2, 6, 7]
arr.extend([8, 0])         # [..., 7, 8, 0]
arr.insert(0, 99)          # [99, 3, 1, ...]
arr.pop()                  # 末尾を取り出して返す
arr.pop(0)                 # 先頭を取り出して返す
arr.remove(1)              # 最初の 1 を削除
arr.index(5)               # 5 の位置 → 4 など
arr.count(1)               # 1 の出現回数

# ソート (in-place)
arr.sort()                 # 昇順
arr.sort(reverse=True)     # 降順
arr.sort(key=abs)          # 絶対値で

# 新しいリストを返すソート
sorted_arr = sorted(arr)
reversed_arr = list(reversed(arr))

リスト内包表記 (List Comprehension)

Python らしい強力な構文。map + filter 相当をワンライナーで、しかも読みやすく書けます。

# 基本: [式 for 変数 in iterable]
squares = [x ** 2 for x in range(10)]
# → [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

# フィルタ付き: [式 for 変数 in iterable if 条件]
evens = [x for x in range(20) if x % 2 == 0]
# → [0, 2, 4, ..., 18]

# 二重ループ
pairs = [(i, j) for i in range(3) for j in range(3) if i != j]
# → [(0,1), (0,2), (1,0), (1,2), (2,0), (2,1)]

# ネスト
matrix = [[i * j for j in range(5)] for i in range(5)]

# 文字列処理
words = ["Apple", "banana", "Cherry"]
upper = [w.upper() for w in words]            # ["APPLE", "BANANA", "CHERRY"]
short = [w for w in words if len(w) <= 5]     # ["Apple"]

# 辞書/集合内包表記もある
square_dict = {x: x ** 2 for x in range(5)}   # {0: 0, 1: 1, ...}
unique_lengths = {len(w) for w in words}      # {5, 6}

# ジェネレータ式 (メモリ効率) — () で囲む
total = sum(x ** 2 for x in range(1_000_000))  # リスト作らず逐次計算

コピー: シャロー vs ディープ

リストを単純代入してもコピーされません。参照が共有されるため、片方を変えるともう片方も変わります。

import copy

a = [1, 2, 3]
b = a                       # 参照共有
b.append(4)
print(a)                    # [1, 2, 3, 4]  ← a も変わる!

# シャローコピー (1 階層のみコピー)
c = a.copy()                # a[:] でも list(a) でも同じ
c.append(5)
print(a)                    # 影響なし

# ネストしているとシャローでは不足
nested = [[1, 2], [3, 4]]
shallow = nested.copy()
shallow[0].append(99)
print(nested)               # [[1, 2, 99], [3, 4]]  ← 内側リストは共有!

# ディープコピー (全階層コピー)
deep = copy.deepcopy(nested)
deep[0].append(99)
print(nested)               # 影響なし

高階関数 map / filter / reduce

関数型のスタイル。シンプルな処理ならリスト内包表記の方が Pythonic ですが、関数を渡したい場合に便利。

from functools import reduce

nums = [1, 2, 3, 4, 5]

# map
doubled = list(map(lambda x: x * 2, nums))         # [2, 4, 6, 8, 10]
# 内包表記なら [x * 2 for x in nums]

# filter
evens = list(filter(lambda x: x % 2 == 0, nums))   # [2, 4]
# 内包表記なら [x for x in nums if x % 2 == 0]

# reduce
total = reduce(lambda acc, x: acc + x, nums, 0)    # 15
# sum(nums) で済む

類似データ構造との違い

可変性得意な操作用途
list可変末尾追加 / インデックスアクセス汎用シーケンス
tuple不変ハッシュ可 (dict キーになれる)固定構造、複数戻り値
collections.deque可変両端 O(1) 追加/削除キュー / スタック
array.array可変同種プリミティブ・省メモリ大量数値の軽量保存
numpy.ndarray可変ベクトル演算 / 多次元数値計算 / ML
set可変重複なし / O(1) 検索集合演算

numpy.array との比較

import numpy as np

# list: 要素ごとに演算するにはループ or 内包表記
nums = [1, 2, 3, 4, 5]
doubled = [x * 2 for x in nums]            # ループが必要

# numpy: ベクトル化演算 (C 実装で高速)
arr = np.array([1, 2, 3, 4, 5])
doubled = arr * 2                          # [2, 4, 6, 8, 10] 一発

# 大量データ (1 M 要素) では numpy が 10〜100 倍速い
big = np.arange(1_000_000)
result = big ** 2 + big * 3                # 一瞬

# 二次元・行列演算
mat = np.array([[1, 2], [3, 4]])
mat @ mat                                  # 行列積
mat.T                                      # 転置

collections.deque (両端キュー)

from collections import deque

# list は左端への挿入が O(n) で遅い
lst = [1, 2, 3]
lst.insert(0, 0)                # O(n) — 全要素を 1 つずらす

# deque は両端 O(1)
dq = deque([1, 2, 3])
dq.appendleft(0)                # O(1)
dq.append(4)                    # O(1)
dq.popleft()                    # O(1)
dq.pop()                        # O(1)

# 最大長指定で「直近 N 件」キャッシュにも使える
recent = deque(maxlen=5)
for i in range(10):
    recent.append(i)
print(recent)                   # deque([5, 6, 7, 8, 9], maxlen=5)

計算量まとめ (Python list)

操作計算量
末尾 append / pop()O(1) 償却
先頭 insert(0, x) / pop(0)O(n)
インデックスアクセス arr[i]O(1)
長さ len(arr)O(1)
連結 a + bO(n + m)
スライス arr[i:j]O(j - i)
包含チェック x in arrO(n)
ソートO(n log n)

FAQ

Q: list * N で多次元リストを作ると挙動が変
A: [[0] * 3] * 2 は同じ内側リストへの参照を 2 つ作ります。[[0] * 3 for _ in range(2)] のように内包表記で個別生成してください。

Q: ソートで安定性は?
A: Python の sort / sorted安定 (Stable, Timsort) です。等しい要素の元の順序が保たれます。

Q: メモリ効率重視で大量の数値を保持したい
A: list は要素ごとにオブジェクト参照 (8 byte/要素) でオーバーヘッドが大。array.array (標準) や numpy.array (推奨) で 10 倍以上のメモリ削減になります。

編集
Post Share
子ページ
  1. リストの作成
  2. 要素の参照
  3. 要素の追加
  4. 要素の更新
  5. 要素の削除
  6. 要素の数を確認
同階層のページ
  1. 基本的なルール
  2. 変数
  3. 演算子
  4. 標準ライブラリ
  5. 外部ライブラリ
  6. 制御構文
  7. リスト(配列)
  8. タプル
  9. セット
  10. 辞書(dict)
  11. クラスとメソッド
  12. 継承の概念と必要性
  13. 継承の構文
  14. コンストラクタ
  15. cookieの値の設定と取得
  16. 例外処理
  17. 例外を文字列で出力する方法
  18. httpリクエスト(curl)をする方法
  19. Responseオブジェクトの中身の確認
  20. 変数が空かどうか判定する方法
  21. タイムゾーンの設定と現在日時の取得と文字列化
  22. シングルクォーテーションとダブルクォーテーションの違い