Skip to content

Python map()関数:例で学ぶイテラブルの変換

Updated on

リストのすべての要素を変換することは、Pythonプログラミングで最も一般的な操作の一つです。整数に変換する必要がある文字列のリストがあります。丸める必要がある価格の列があります。小文字にすべきファイル名のセットがあります。本能的にforループを書いて、空のリストを作成し、各結果を追加して、リストを返します。動作しますが、冗長でエラーが起きやすく、実際の変換ロジックを定型コードの中に埋もれさせてしまいます。

Pythonの組み込み map() 関数はこの定型コードを排除します。関数と一つ以上のイテラブルを受け取り、関数をすべての要素に適用し、結果のイテレータを返します。一行が五行を置き換えます。コードは、やり方ではなく、何をしたいかの説明のように読めます。

📚

このガイドでは、Python map関数のすべての実践的な側面を網羅します:基本的な構文、lambdaや組み込み関数とのmapの組み合わせ、複数イテラブルの操作、リスト内包表記とのパフォーマンス比較、そして本番コードで使用する実世界のデータ処理パターンです。

map()の基本構文

map() 関数のシグネチャはシンプルです:

map(function, iterable, *iterables)
  • function -- 一つの引数を受け取る呼び出し可能なオブジェクト(複数のイテラブルを渡す場合はそれ以上)。
  • iterable -- 要素が function に渡されるシーケンス。
  • *iterables -- オプションの追加イテラブル。指定された場合、function はその数の引数を受け入れる必要があります。

map()mapオブジェクト を返します。これは遅延イテレータです。すべての結果を即座に計算しません。代わりに、消費するときに一つずつ値を生成します。

最もシンプルな例を示します:

numbers = [1, 2, 3, 4, 5]
squared = map(lambda x: x ** 2, numbers)
 
print(squared)
# <map object at 0x...>
 
print(list(squared))
# [1, 4, 9, 16, 25]

mapオブジェクトは結果を直接表示しません。リスト、タプル、または他のコレクションに変換するか、ループで反復処理します。

map()と組み込み関数

map() の最もクリーンな使い方の一つは、Pythonの組み込み関数と組み合わせることです。lambdaは不要です -- 関数名を直接渡すだけです。

int, float, strによる型変換

# 文字列を整数に変換
string_numbers = ["10", "20", "30", "40"]
integers = list(map(int, string_numbers))
print(integers)
# [10, 20, 30, 40]
 
# 整数を浮動小数点数に変換
values = [1, 2, 3, 4]
floats = list(map(float, values))
print(floats)
# [1.0, 2.0, 3.0, 4.0]
 
# 数値を文字列に変換
ids = [101, 102, 103]
string_ids = list(map(str, ids))
print(string_ids)
# ['101', '102', '103']

lenで長さを取得

words = ["Python", "map", "function", "tutorial"]
lengths = list(map(len, words))
print(lengths)
# [6, 3, 8, 8]

str.stripで空白を除去

raw_inputs = ["  hello  ", "  world ", " python  "]
cleaned = list(map(str.strip, raw_inputs))
print(cleaned)
# ['hello', 'world', 'python']

その他の便利な組み込み関数の組み合わせ

# abs()で絶対値
numbers = [-5, 3, -1, 7, -2]
absolutes = list(map(abs, numbers))
print(absolutes)
# [5, 3, 1, 7, 2]
 
# round()で四捨五入(引数一つの形式)
prices = [19.995, 4.123, 99.876]
rounded = list(map(round, prices))
print(rounded)
# [20, 4, 100]
 
# bool()で真偽値判定
values = [0, 1, "", "hello", None, [], [1]]
truthy = list(map(bool, values))
print(truthy)
# [False, True, False, True, False, False, True]

組み込み関数が必要な処理をすでに行える場合、map() に直接渡してください。lambdaでラップする理由はありません。

map()とlambda関数

lambda関数は map() の完全な力を引き出します。名前付き関数を作成せずにインライン変換を定義できます。

# 各数値を二乗する
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x ** 2, numbers))
print(squared)
# [1, 4, 9, 16, 25]
 
# 摂氏から華氏へ
celsius = [0, 20, 37, 100]
fahrenheit = list(map(lambda c: round(c * 9/5 + 32, 1), celsius))
print(fahrenheit)
# [32.0, 68.0, 98.6, 212.0]
 
# メールアドレスからドメインを抽出
emails = ["alice@gmail.com", "bob@company.org", "carol@university.edu"]
domains = list(map(lambda e: e.split("@")[1], emails))
print(domains)
# ['gmail.com', 'company.org', 'university.edu']
 
# 名前をフォーマット
names = ["alice smith", "bob jones", "carol white"]
formatted = list(map(lambda n: n.title(), names))
print(formatted)
# ['Alice Smith', 'Bob Jones', 'Carol White']

パターンは一貫しています:map(lambda x: transform(x), iterable)。lambdaの本体は単一の明確な式にしてください。変換に複数のステップが必要な場合は、代わりに名前付き関数を使用してください。

map()と複数のイテラブル

複数のイテラブルを渡すと、map() は各イテラブルから一つずつ要素を取って並列に関数を呼び出します。関数はイテラブルの数と同じ数の引数を受け入れる必要があります。イテレーションは最短のイテラブルが使い果たされたときに停止します。

# 二つのリストの対応する要素を加算
list_a = [1, 2, 3, 4]
list_b = [10, 20, 30, 40]
sums = list(map(lambda a, b: a + b, list_a, list_b))
print(sums)
# [11, 22, 33, 44]
 
# 重み付きスコアを計算
scores = [85, 92, 78, 95]
weights = [0.3, 0.3, 0.2, 0.2]
weighted = list(map(lambda s, w: round(s * w, 1), scores, weights))
print(weighted)
# [25.5, 27.6, 15.6, 19.0]
 
# 姓と名を結合
first_names = ["Ada", "Grace", "Alan"]
last_names = ["Lovelace", "Hopper", "Turing"]
full_names = list(map(lambda f, l: f"{f} {l}", first_names, last_names))
print(full_names)
# ['Ada Lovelace', 'Grace Hopper', 'Alan Turing']

三つ以上のイテラブル

# 三つの寸法リストから体積を計算
lengths = [2, 3, 4]
widths = [5, 6, 7]
heights = [8, 9, 10]
 
volumes = list(map(lambda l, w, h: l * w * h, lengths, widths, heights))
print(volumes)
# [80, 162, 280]

不揃いな長さの処理

map() は最短のイテラブルで停止します。エラーなし、パディングなし -- 単に停止します:

a = [1, 2, 3, 4, 5]
b = [10, 20, 30]
result = list(map(lambda x, y: x + y, a, b))
print(result)
# [11, 22, 33]
# 'a'の要素4と5は暗黙的に無視される

不揃いな長さを明示的に処理する必要がある場合は、itertools.zip_longest を使用してください:

from itertools import zip_longest
 
a = [1, 2, 3, 4, 5]
b = [10, 20, 30]
result = list(map(lambda pair: pair[0] + (pair[1] or 0), zip_longest(a, b, fillvalue=0)))
print(result)
# [11, 22, 33, 4, 5]

map() vs リスト内包表記

これが最も重要な比較です。map() とリスト内包表記はどちらもシーケンスを変換しますが、異なる強みを持っています。

特徴map()リスト内包表記
構文map(func, iterable)[func(x) for x in iterable]
可読性(シンプルな変換)組み込み関数で高いすべてのケースで高い
可読性(複雑な変換)低い(ネストしたlambda)高い(複数行可能)
フィルタリングサポートなし(別途 filter() が必要)あり(if 句組み込み)
戻り値の型遅延イテレータ(mapオブジェクト)即時リスト
大量データのメモリ少ない(遅延評価)多い(全リストがメモリに)
速度(組み込み関数)速い(Python レベルの呼び出しなし)やや遅い
速度(lambda関数)同等同等またはやや速い
ネストした変換チェーンが不便ネストが自然
デバッグ難しい(遅延、中間リストなし)簡単(即時結果)

パフォーマンスベンチマーク

import timeit
 
data = list(range(100_000))
 
# 組み込み関数でmap
time_map_builtin = timeit.timeit(
    'list(map(str, data))',
    globals={'data': data},
    number=100
)
 
# 組み込み関数でリスト内包表記
time_comp_builtin = timeit.timeit(
    '[str(x) for x in data]',
    globals={'data': data},
    number=100
)
 
# lambdaでmap
time_map_lambda = timeit.timeit(
    'list(map(lambda x: x * 2, data))',
    globals={'data': data},
    number=100
)
 
# リスト内包表記の等価版
time_comp_expr = timeit.timeit(
    '[x * 2 for x in data]',
    globals={'data': data},
    number=100
)
 
print(f"map + 組み込み:    {time_map_builtin:.4f}s")
print(f"内包表記:          {time_comp_builtin:.4f}s")
print(f"map + lambda:      {time_map_lambda:.4f}s")
print(f"内包表記:          {time_comp_expr:.4f}s")
# 典型的な結果:
# map + 組み込み:    ~0.85s(速い)
# 内包表記:          ~1.05s
# map + lambda:      ~0.95s
# 内包表記:          ~0.80s(速い)

重要な洞察:map() を組み込み関数(intstrfloat など)と使う場合、各イテレーションでPythonレベルの関数呼び出しを避けるため、より高速です。しかし map() をlambdaと使う場合は、リスト内包表記とほぼ同じ速度か、わずかに遅くなります。どちらも要素ごとにPythonレベルの関数呼び出しを伴うためです。

map() vs ジェネレータ式

結果リスト全体をメモリに保持する必要がない場合、map() とジェネレータ式の両方が遅延評価を提供します:

# mapオブジェクト - 遅延
mapped = map(lambda x: x ** 2, range(1_000_000))
 
# ジェネレータ式 - 遅延
generated = (x ** 2 for x in range(1_000_000))
 
# どちらもイテレーション時のみメモリを消費
for value in mapped:
    if value > 100:
        break

違いはスタイル上のものです。ジェネレータ式はほとんどのPython開発者にとってより自然に読め、if 句でのフィルタリングをサポートします。適用する名前付き関数がすでにある場合は map() を使い、そうでなければジェネレータ式を使用してください。

# 名前付き関数がある場合はmapがクリーン
import math
roots = map(math.sqrt, range(10))
 
# 式の場合はジェネレータがクリーン
roots = (x ** 0.5 for x in range(10))

mapオブジェクトをlist、tuple、setに変換

mapオブジェクトはイテレータです。結果を具体化するには、明示的に変換します:

numbers = [1, 2, 3, 2, 4, 3, 5]
 
# リストに(順序を保持、重複を許可)
as_list = list(map(lambda x: x * 10, numbers))
print(as_list)
# [10, 20, 30, 20, 40, 30, 50]
 
# タプルに(イミュータブルなシーケンス)
as_tuple = tuple(map(lambda x: x * 10, numbers))
print(as_tuple)
# (10, 20, 30, 20, 40, 30, 50)
 
# セットに(重複を除去、順序なし)
as_set = set(map(lambda x: x * 10, numbers))
print(as_set)
# {10, 20, 30, 40, 50}

重要: mapオブジェクトは一度しか消費できません。リストに変換した後、再度イテレーションしても何も得られません:

mapped = map(str, [1, 2, 3])
first = list(mapped)
second = list(mapped)
print(first)   # ['1', '2', '3']
print(second)  # [] -- すでに使い果たされた

map()とカスタム関数

lambdaには複雑すぎる変換の場合、通常の関数を定義して map() に渡します:

def parse_temperature(reading):
    """温度読み取り文字列を標準化された辞書に変換する。"""
    value, unit = float(reading[:-1]), reading[-1]
    if unit == 'F':
        celsius = round((value - 32) * 5 / 9, 1)
    elif unit == 'C':
        celsius = value
    elif unit == 'K':
        celsius = round(value - 273.15, 1)
    else:
        raise ValueError(f"不明な単位: {unit}")
    return {"original": reading, "celsius": celsius}
 
readings = ["98.6F", "37.0C", "310.0K", "72.0F"]
parsed = list(map(parse_temperature, readings))
 
for entry in parsed:
    print(f"{entry['original']} -> {entry['celsius']}°C")
# 98.6F -> 37.0°C
# 37.0C -> 37.0°C
# 310.0K -> 36.9°C
# 72.0F -> 22.2°C

このパターンは map() の呼び出しをクリーンに保ちながら、複雑なロジックをテスト可能で文書化された関数に移動します。

def normalize_record(record):
    """ユーザーレコードをデータベース挿入用に標準化する。"""
    return {
        "name": record["name"].strip().title(),
        "email": record["email"].strip().lower(),
        "age": int(record["age"]),
        "active": record.get("active", True),
    }
 
raw_records = [
    {"name": "  alice smith ", "email": "ALICE@Email.COM", "age": "30"},
    {"name": "bob jones", "email": "Bob@Work.ORG  ", "age": "25"},
]
 
clean_records = list(map(normalize_record, raw_records))
for r in clean_records:
    print(r)
# {'name': 'Alice Smith', 'email': 'alice@email.com', 'age': 30, 'active': True}
# {'name': 'Bob Jones', 'email': 'bob@work.org', 'age': 25, 'active': True}

map()呼び出しのチェーン

map() はイテレータを返すため、複数の map() 呼び出しをチェーンして変換パイプラインを構築できます。各ステップは中間リストを作成せずに一度に一つの要素を処理します:

raw_data = ["  42  ", " 17 ", "  89  ", " 3  "]
 
# チェーン:空白除去 -> intに変換 -> 値を倍にする
result = map(str.strip, raw_data)
result = map(int, result)
result = map(lambda x: x * 2, result)
 
print(list(result))
# [84, 34, 178, 6]

可読性のために、呼び出しをネストできます(内側から外側へ読む):

raw_data = ["  42  ", " 17 ", "  89  ", " 3  "]
 
result = list(map(lambda x: x * 2, map(int, map(str.strip, raw_data))))
print(result)
# [84, 34, 178, 6]

ネストバージョンはコンパクトですが読みにくくなります。シーケンシャルバージョンはマルチステップパイプラインには明確です。どちらも中間リストを作成しません -- 三つのmapオブジェクトすべてが遅延評価されます。

データ処理パイプラインでのmap()

実世界のデータ処理では、データの読み取り、クリーニング、変換、集約がよく行われます。map() はこのパターンに自然に適合します。

ログエントリの処理

log_lines = [
    "2026-02-10 INFO User logged in",
    "2026-02-10 ERROR Database timeout",
    "2026-02-10 WARNING Disk space low",
    "2026-02-10 INFO File uploaded",
]
 
def parse_log(line):
    parts = line.split(" ", 2)
    return {"date": parts[0], "level": parts[1], "message": parts[2]}
 
parsed = list(map(parse_log, log_lines))
errors = list(filter(lambda entry: entry["level"] == "ERROR", parsed))
print(errors)
# [{'date': '2026-02-10', 'level': 'ERROR', 'message': 'Database timeout'}]

バッチファイルリネームロジック

import os
 
filenames = ["Report Q1.PDF", "data export.CSV", "NOTES 2026.TXT"]
 
def sanitize_filename(name):
    base, ext = os.path.splitext(name)
    return base.strip().lower().replace(" ", "_") + ext.lower()
 
cleaned = list(map(sanitize_filename, filenames))
print(cleaned)
# ['report_q1.pdf', 'data_export.csv', 'notes_2026.txt']

数値データパイプライン

import math
 
raw_measurements = ["3.14159", "2.71828", "1.41421", "1.73205"]
 
# パイプライン:パース -> 二乗 -> 対数 -> 小数点3桁に丸め
pipeline = map(lambda x: round(x, 3),
           map(math.log,
           map(lambda x: x ** 2,
           map(float, raw_measurements))))
 
print(list(pipeline))
# [2.292, 2.003, 0.693, 1.099]

map() vs リスト内包表記の使い分けガイド

状況に合ったツールを選ぶためのクイックリファレンス:

map() を使う場合:

  • 単一の組み込み関数を適用する:map(int, strings)map(str.strip, lines)
  • 変換を行う名前付き関数がすでにある
  • 遅延評価が必要で、完全なリストをメモリに保持する必要がない
  • 要素ごとの操作のために複数のイテラブルを渡す

リスト内包表記を使う場合:

  • 変換がシンプルな式:[x * 2 for x in numbers]
  • 同じステップでフィルタリングが必要:[x for x in items if x > 0]
  • ロジックが複数の条件やネストした操作を含む
  • 結果をすぐにリストとして欲しい
  • マイクロ最適化よりも可読性が重要

ジェネレータ式を使う場合:

  • 遅延評価が必要だが内包表記構文の可読性が欲しい
  • 結果が一度しか消費されない(sum()max()join() などに渡す)
# map -- 型変換に最もクリーン
integers = list(map(int, ["1", "2", "3"]))
 
# リスト内包表記 -- 変換 + フィルタに最もクリーン
even_squares = [x ** 2 for x in range(20) if x % 2 == 0]
 
# ジェネレータ式 -- 一回限りの消費に最もクリーン
total = sum(x ** 2 for x in range(1000))

RunCellでmap()を実験する

map() でデータ変換パイプラインを構築する際、各段階をインタラクティブにテストすることが不可欠です。中間結果を確認し、エッジケースをチェックし、チェーンされたmapが期待通りの出力を生成するか検証する必要があります。

RunCell (opens in a new tab) は、Jupyterノートブック内で直接実行されるAIエージェントです。ノートブックのコンテキスト -- メモリ内の変数、DataFrame、インポート -- を理解し、map() パイプラインをステップバイステップで構築してデバッグするのを支援します:

  • 中間結果の可視化。 チェーンされた map() の各段階が何を生成するかをRunCellに表示させます。パイプラインを壊すことなく確認できます。
  • ベクトル化された代替案の提案。 pandas Seriesで map() を使用している場合、RunCellは10〜100倍速いネイティブpandas操作を推奨できます。
  • mapと内包表記の変換。 変換を説明すると、RunCellが両方のバージョンを生成し、より読みやすい方を選べます。
  • エッジケースのデバッグ。 予期しない入力(None値、空文字列、混合型)をmapパイプラインに投入し、正確にどこで壊れるか確認できます。

FAQ

Pythonのmap()関数は何をしますか?

map() 関数は、一つ以上のイテラブル(リスト、タプル、文字列など)の各要素に与えられた関数を適用し、結果のイテレータを返します。明示的なループを書かずに関数型スタイルのデータ変換を可能にする組み込み関数です。構文は map(function, iterable) で、返されるmapオブジェクトは遅延型です -- 一度にすべてではなく、必要に応じて結果を計算します。

Pythonでmap()はforループより速いですか?

はい、map()append() でリストを構築する同等のforループよりも一般的に高速です。速度の優位性は map() がインタプリタレベルでCで実装されていることに起因し、Pythonレベルのループイテレーションとメソッド呼び出しのオーバーヘッドを回避します。intstr のような組み込み関数と map() を使用する場合、パフォーマンスの向上は最も顕著で、通常20〜40%高速です。lambdaの場合、lambda自体がPythonレベルの関数呼び出しを導入するため、差は縮まります。

mapオブジェクトをリストに変換するにはどうしますか?

map() の呼び出しを list() でラップします:result = list(map(int, strings))。他のコレクションにも変換できます:タプルには tuple(map(...))、セットには set(map(...))。mapオブジェクトは一回使い切りのイテレータであることを覚えておいてください。消費された後(リストに変換するかイテレーションした後)は、使い果たされて再利用できません。

map()は複数のリストで動作しますか?

はい。関数の後に複数のイテラブルを渡します:map(func, list1, list2, list3)。関数はイテラブルの数と同じ数の引数を受け入れる必要があります。例えば、list(map(lambda a, b: a + b, [1, 2], [10, 20]))[11, 22] を返します。イテレーションは最短のイテラブルで停止するため、長さが異なるリストでもエラーは発生しません -- 余分な要素は暗黙的に無視されます。

map()とリスト内包表記のどちらを使うべきですか?

単一の既存関数(組み込みまたは名前付き)をイテラブルに適用する場合、特に map(int, strings) のような型変換には map() を使用してください。変換が式を含む場合、if 句でフィルタリングが必要な場合、または可読性が優先される場合はリスト内包表記を使用してください。現代のPythonでは、リスト内包表記がほとんどの開発者のデフォルトの選択肢ですが、組み込み関数との map() はシンプルな一関数変換には依然としてより速く簡潔です。

まとめ

Pythonの map() 関数は、特定の仕事のための精密なツールです:ループを書かずにイテラブルの各要素に単一の関数を適用すること。intstrfloatlen のような組み込み関数と組み合わせたときに最も読みやすく高速なコードを生成します。lambda関数ではインライン変換をクリーンに処理します。複数のイテラブルでは、本来 zip() とループが必要な要素ごとの操作を処理します。

map() を効果的に使うためのルール:

  • 組み込み関数は直接渡す:map(int, strings) であって map(lambda x: int(x), strings) ではない。
  • lambdaはシンプルな単一式の変換にのみ使用する。
  • 変換にエラー処理、複数のステップ、またはドキュメントが必要な場合は名前付き関数に切り替える。
  • フィルタリングが必要な場合や、式がインラインでより明確な場合はリスト内包表記を優先する。
  • map() が遅延型の一回使い切りイテレータを返すことを忘れない -- 結果を再利用または検査する必要がある場合は list() に変換する。
  • 中間リストを作成せずにマルチステップパイプラインのために map() 呼び出しをチェーンする。

map() はリスト内包表記の代替ではなく、リスト内包表記は map() の代替ではありません。重なりはありますが、異なる強みに対応しています。最良のPythonコードは、それぞれが自然に適合する場所で使用します:既存の関数を適用するには map()、式とフィルタリングにはリスト内包表記、遅延型の一回限りの消費にはジェネレータ式です。

📚