「リストの中から特定の条件に合うデータだけを取り出したい」
Pythonを使っていると、そんな場面に必ず出会います。
よくある処理例:
- 偶数だけを抽出したい
- 空文字列を除去したい
- 特定の条件に合うユーザーだけを取得したい
- ログから特定のレベルだけを表示したい
従来の方法との比較:
# for文での書き方(冗長)
numbers = [1, 2, 3, 4, 5, 6]
even_numbers = []
for n in numbers:
if n % 2 == 0:
even_numbers.append(n)
# filter()なら1行でスッキリ
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
そんなときに便利なのが、組み込み関数filter()
です。
for
文やリスト内包表記よりもスッキリ書けて、読みやすく効率的なコードにすることができます。
この記事では、Pythonのfilter()
関数の基本構文・使い方・ラムダ式との組み合わせ方・注意点・実践例までを、初心者向けにやさしく解説します。
第1章:filter()関数とは?基本構文と使い方

filter()の基本構文
filter(関数, イテラブル)
パラメータの説明:
- 関数:各要素に対してTrue/Falseを返す関数
- イテラブル:リストやタプル、文字列など反復可能なオブジェクト
戻り値: フィルタされた要素(引数の関数でTrueを返した要素)を含むイテレータ(filterオブジェクト)
基本的な使用例
例1:偶数だけを取り出す
def is_even(n):
"""偶数かどうかを判定する関数"""
return n % 2 == 0
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
result = filter(is_even, numbers)
# 結果をリストに変換して表示
print(list(result)) # [2, 4, 6, 8, 10]
例2:正の数だけを取り出す
def is_positive(n):
"""正の数かどうかを判定する関数"""
return n > 0
numbers = [-3, -1, 0, 1, 2, 5]
positive_numbers = list(filter(is_positive, numbers))
print(positive_numbers) # [1, 2, 5]
例3:文字列の長さでフィルタ
def is_long_word(word):
"""4文字以上の単語かどうかを判定"""
return len(word) >= 4
words = ["cat", "dog", "elephant", "bird", "butterfly"]
long_words = list(filter(is_long_word, words))
print(long_words) # ['elephant', 'bird', 'butterfly']
filter()の動作イメージ
# filter()が内部で行っている処理のイメージ
def my_filter(func, iterable):
"""filter()の簡単な実装例"""
result = []
for item in iterable:
if func(item): # 関数がTrueを返す場合のみ
result.append(item)
return result
# 使用例
numbers = [1, 2, 3, 4, 5]
result = my_filter(lambda x: x % 2 == 0, numbers)
print(result) # [2, 4]
第2章:filter() × lambda の書き方と活用例
ラムダ式とは?
ラムダ式は、関数をその場で定義するための匿名関数です。
# 通常の関数定義
def double(x):
return x * 2
# ラムダ式での定義
double_lambda = lambda x: x * 2
print(double(5)) # 10
print(double_lambda(5)) # 10
filter()とlambdaの組み合わせ
例1:偶数の抽出をlambdaで
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 通常の関数を使った場合
def is_even(n):
return n % 2 == 0
result1 = list(filter(is_even, numbers))
# lambdaを使った場合(1行で完結)
result2 = list(filter(lambda x: x % 2 == 0, numbers))
print(result1) # [2, 4, 6, 8, 10]
print(result2) # [2, 4, 6, 8, 10]
例2:文字列のフィルタリング
# 特定の文字を含む単語を抽出
words = ["apple", "banana", "avocado", "berry", "cherry"]
# 'a'を含む単語を抽出
words_with_a = list(filter(lambda word: "a" in word, words))
print(words_with_a) # ['apple', 'banana', 'avocado']
# 5文字以上の単語を抽出
long_words = list(filter(lambda word: len(word) >= 5, words))
print(long_words) # ['apple', 'banana', 'avocado', 'berry', 'cherry']
# 'b'で始まる単語を抽出
b_words = list(filter(lambda word: word.startswith('b'), words))
print(b_words) # ['banana', 'berry']
例3:数値の範囲指定
temperatures = [15, 22, 28, 35, 18, 42, 12, 30]
# 20度以上30度以下の快適な温度を抽出
comfortable_temps = list(filter(lambda temp: 20 <= temp <= 30, temperatures))
print(comfortable_temps) # [22, 28, 30]
# 極端な温度(15度以下または35度以上)を抽出
extreme_temps = list(filter(lambda temp: temp <= 15 or temp >= 35, temperatures))
print(extreme_temps) # [15, 35, 42, 12]
複雑な条件での活用
# 辞書のリストから特定の条件でフィルタ
students = [
{"name": "Alice", "age": 20, "grade": 85},
{"name": "Bob", "age": 22, "grade": 75},
{"name": "Charlie", "age": 19, "grade": 95},
{"name": "Diana", "age": 21, "grade": 65}
]
# 80点以上の学生を抽出
high_achievers = list(filter(lambda student: student["grade"] >= 80, students))
print(high_achievers)
# [{'name': 'Alice', 'age': 20, 'grade': 85}, {'name': 'Charlie', 'age': 19, 'grade': 95}]
# 20歳以上で70点以上の学生を抽出
qualified_students = list(filter(
lambda student: student["age"] >= 20 and student["grade"] >= 70,
students
))
print(qualified_students)
# [{'name': 'Alice', 'age': 20, 'grade': 85}, {'name': 'Bob', 'age': 22, 'grade': 75}]
第3章:filterとリスト内包表記の違いと使い分け

同じ処理の異なる書き方
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 方法1: filter() + lambda
even_numbers_filter = list(filter(lambda x: x % 2 == 0, numbers))
# 方法2: リスト内包表記
even_numbers_comprehension = [x for x in numbers if x % 2 == 0]
# 方法3: 従来のfor文
even_numbers_loop = []
for x in numbers:
if x % 2 == 0:
even_numbers_loop.append(x)
print(even_numbers_filter) # [2, 4, 6, 8, 10]
print(even_numbers_comprehension) # [2, 4, 6, 8, 10]
print(even_numbers_loop) # [2, 4, 6, 8, 10]
filter()の利点
1. 可読性が高い
# filter(): 「フィルタする処理」だと一目で分かる
valid_emails = list(filter(is_valid_email, email_list))
# リスト内包表記: 慣れていないと読みにくい場合がある
valid_emails = [email for email in email_list if is_valid_email(email)]
2. 関数の再利用性
def is_adult(person):
return person["age"] >= 18
# 複数の場所で同じ条件を使い回せる
adults_list1 = list(filter(is_adult, customers))
adults_list2 = list(filter(is_adult, employees))
adults_list3 = list(filter(is_adult, visitors))
3. 関数型プログラミングのスタイル
# map(), filter(), reduce() の組み合わせ
from functools import reduce
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
result = reduce(
lambda x, y: x + y, # 合計を計算
map(
lambda x: x ** 2, # 二乗する
filter(lambda x: x % 2 == 0, numbers) # 偶数だけ抽出
)
)
print(result) # 220 (2^2 + 4^2 + 6^2 + 8^2 + 10^2)
リスト内包表記の利点
1. 結果がすぐリストになる
# filter(): list()で変換が必要
result = list(filter(lambda x: x > 0, numbers))
# リスト内包表記: 直接リストが得られる
result = [x for x in numbers if x > 0]
2. 変換とフィルタが同時にできる
numbers = [1, 2, 3, 4, 5]
# リスト内包表記: フィルタ + 変換が1行
squares_of_evens = [x**2 for x in numbers if x % 2 == 0]
# filter() + map(): 2段階の処理
squares_of_evens = list(map(lambda x: x**2, filter(lambda x: x % 2 == 0, numbers)))
3. Pythonらしい記述
# Pythonコミュニティでよく見かける書き方
positive_numbers = [x for x in numbers if x > 0]
使い分けの指針
条件 | おすすめ | 理由 |
---|---|---|
シンプルな条件 | リスト内包表記 | 簡潔で読みやすい |
複雑な条件関数 | filter() | 関数の再利用性 |
フィルタのみ | filter() | 意図が明確 |
フィルタ + 変換 | リスト内包表記 | 1行で完結 |
関数型スタイル | filter() | map(), reduce()との組み合わせ |
大量データ | filter() | イテレータによるメモリ効率 |
第4章:filter()を使うときの注意点とよくあるミス
注意①:filterの戻り値はリストではなく「イテレータ」
numbers = [-1, 0, 1, 2, 3]
result = filter(lambda x: x > 0, numbers)
print(result) # <filter object at 0x...>
print(type(result)) # <class 'filter'>
# リストとして使いたい場合は変換が必要
result_list = list(result)
print(result_list) # [1, 2, 3]
print(type(result_list)) # <class 'list'>
注意②:イテレータは一度使うと使い切り(再利用不可)
numbers = [-1, 0, 1, 2, 3]
filtered = filter(lambda x: x > 0, numbers)
print(list(filtered)) # [1, 2, 3]
print(list(filtered)) # [] ← 空になる!
# 再利用したい場合はリストに変換
filtered_list = list(filter(lambda x: x > 0, numbers))
print(filtered_list) # [1, 2, 3]
print(filtered_list) # [1, 2, 3] ← 何度でも使える
注意③:関数がNoneの場合の特殊な動作
# Noneを渡すと「真偽値がTrue」の要素を残す
data = ["", "hello", 0, 42, None, "world", False, True]
result = list(filter(None, data))
print(result) # ['hello', 42, 'world', True]
# これは以下と同じ意味
result = list(filter(lambda x: bool(x), data))
print(result) # ['hello', 42, 'world', True]
真偽値の判定基準:
# False として判定される値
falsy_values = [False, 0, 0.0, "", [], {}, None]
for value in falsy_values:
print(f"{repr(value)}: {bool(value)}")
# 出力:
# False: False
# 0: False
# 0.0: False
# '': False
# []: False
# {}: False
# None: False
注意④:変更可能なオブジェクトの扱い
# リストの要素が変更可能オブジェクトの場合
people = [
{"name": "Alice", "age": 25},
{"name": "Bob", "age": 17},
{"name": "Charlie", "age": 30}
]
adults = list(filter(lambda person: person["age"] >= 18, people))
print(adults)
# [{'name': 'Alice', 'age': 25}, {'name': 'Charlie', 'age': 30}]
# 元のリストと同じオブジェクトを参照している
adults[0]["age"] = 26
print(people[0]) # {'name': 'Alice', 'age': 26} ← 元のリストも変更される
# 新しいオブジェクトを作りたい場合
import copy
adults_copy = [copy.deepcopy(person) for person in people if person["age"] >= 18]
パフォーマンスに関する注意
import time
# 大量データでのパフォーマンス比較
large_numbers = list(range(1000000))
# filter() + list() の場合
start = time.time()
result1 = list(filter(lambda x: x % 2 == 0, large_numbers))
time1 = time.time() - start
# リスト内包表記の場合
start = time.time()
result2 = [x for x in large_numbers if x % 2 == 0]
time2 = time.time() - start
print(f"filter(): {time1:.4f}秒")
print(f"リスト内包表記: {time2:.4f}秒")
# 一般的にリスト内包表記の方が高速
第5章:実践的なfilter()の活用例

データクリーニング
# CSVデータの前処理例
raw_data = [
{"name": "Alice", "email": "alice@example.com", "age": 25},
{"name": "", "email": "invalid-email", "age": 30},
{"name": "Bob", "email": "bob@example.com", "age": -5},
{"name": "Charlie", "email": "charlie@example.com", "age": 35},
{"name": None, "email": "", "age": 40}
]
def is_valid_record(record):
"""有効なレコードかどうかを判定"""
return (
record.get("name") and # 名前が存在し、空でない
"@" in record.get("email", "") and # 有効なメール形式
record.get("age", 0) > 0 # 年齢が正の数
)
clean_data = list(filter(is_valid_record, raw_data))
print(clean_data)
# [{'name': 'Alice', 'email': 'alice@example.com', 'age': 25},
# {'name': 'Charlie', 'email': 'charlie@example.com', 'age': 35}]
ログファイルの解析
# ログエントリの処理例
log_entries = [
{"timestamp": "2024-01-01 10:00:00", "level": "INFO", "message": "Application started"},
{"timestamp": "2024-01-01 10:01:00", "level": "DEBUG", "message": "Processing request"},
{"timestamp": "2024-01-01 10:02:00", "level": "ERROR", "message": "Database connection failed"},
{"timestamp": "2024-01-01 10:03:00", "level": "WARNING", "message": "High memory usage"},
{"timestamp": "2024-01-01 10:04:00", "level": "ERROR", "message": "Timeout occurred"}
]
# エラーレベルのログのみ抽出
error_logs = list(filter(lambda log: log["level"] == "ERROR", log_entries))
print("エラーログ:")
for log in error_logs:
print(f" {log['timestamp']}: {log['message']}")
# WARNING以上のレベル(WARNING, ERROR)を抽出
important_levels = ["WARNING", "ERROR"]
important_logs = list(filter(lambda log: log["level"] in important_levels, log_entries))
print("\n重要なログ:")
for log in important_logs:
print(f" [{log['level']}] {log['timestamp']}: {log['message']}")
Webアプリケーションでの使用例
# ユーザー管理システムの例
users = [
{"id": 1, "username": "alice", "email": "alice@example.com", "is_active": True, "role": "admin"},
{"id": 2, "username": "bob", "email": "bob@example.com", "is_active": False, "role": "user"},
{"id": 3, "username": "charlie", "email": "charlie@example.com", "is_active": True, "role": "user"},
{"id": 4, "username": "diana", "email": "diana@example.com", "is_active": True, "role": "moderator"}
]
def get_active_users(users):
"""アクティブなユーザーのみを取得"""
return list(filter(lambda user: user["is_active"], users))
def get_admins(users):
"""管理者のみを取得"""
return list(filter(lambda user: user["role"] == "admin", users))
def search_users_by_email_domain(users, domain):
"""指定ドメインのメールアドレスを持つユーザーを検索"""
return list(filter(lambda user: user["email"].endswith(f"@{domain}"), users))
# 使用例
active_users = get_active_users(users)
admins = get_admins(users)
example_users = search_users_by_email_domain(users, "example.com")
print(f"アクティブユーザー: {len(active_users)}人")
print(f"管理者: {len(admins)}人")
print(f"example.comドメインのユーザー: {len(example_users)}人")
ファイル処理での活用
import os
from pathlib import Path
def filter_files_by_extension(directory, extension):
"""指定した拡張子のファイルのみを取得"""
all_files = os.listdir(directory)
return list(filter(lambda filename: filename.endswith(extension), all_files))
def filter_large_files(file_paths, min_size_mb=1):
"""指定サイズ以上のファイルのみを取得"""
min_size_bytes = min_size_mb * 1024 * 1024
def is_large_file(filepath):
try:
return os.path.getsize(filepath) >= min_size_bytes
except OSError:
return False
return list(filter(is_large_file, file_paths))
# 使用例(実際のディレクトリがある場合)
# python_files = filter_files_by_extension(".", ".py")
# large_files = filter_large_files(python_files, 0.1) # 0.1MB以上
まとめ:filter()を使いこなして効率的な条件抽出をしよう!
filter()
は、特定の条件に一致するデータだけを取り出すのに最適なPythonの組み込み関数です。
特に、lambdaと組み合わせることで、シンプルかつ読みやすいコードを実現できます。
本記事の重要ポイント
基本的な使い方:
filter(関数, イテラブル)
で条件に合う要素だけを抽出- 戻り値はイテレータなので、リストが必要なら
list()
で変換 - lambdaとの組み合わせで簡潔な記述が可能
特殊な使い方:
filter(None, iterable)
で真偽値がTrueの要素のみを抽出- 複雑な条件も関数として定義すれば再利用可能
注意すべきポイント:
- イテレータは使い切り:再利用したい場合はリストに変換
- パフォーマンス:大量データではリスト内包表記の方が高速な場合も
- オブジェクトの参照:フィルタ結果も元のオブジェクトを参照
コメント