Skip to content

Python map() Function: Transform Iterables with Examples

Updated on

Transforming every element in a list is one of the most common operations in Python programming. You have a list of strings that need to be converted to integers. A column of prices that must be rounded. A set of filenames that should be lowercased. The instinct is to write a for loop, create an empty list, append each result, and return the list. It works, but it is verbose, error-prone, and buries the actual transformation logic inside boilerplate code.

Python's built-in map() function eliminates this boilerplate. It takes a function and one or more iterables, applies the function to every element, and returns an iterator of results. One line replaces five. The code reads like a description of what you want, not how to do it.

📚

This guide covers every practical aspect of the Python map function: the basic syntax, combining map with lambda and built-in functions, working with multiple iterables, performance comparisons against list comprehensions, and real-world data processing patterns you will use in production code.

Basic Syntax of map()

The map() function signature is straightforward:

map(function, iterable, *iterables)
  • function -- a callable that accepts one argument (or more, if you pass multiple iterables).
  • iterable -- the sequence whose elements will be passed to function.
  • *iterables -- optional additional iterables. When provided, function must accept that many arguments.

map() returns a map object, which is a lazy iterator. It does not compute all results immediately. Instead, it produces values one at a time as you consume them.

Here is the simplest possible example:

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]

The map object does not display results directly. You convert it to a list, tuple, or other collection, or iterate through it in a loop.

map() with Built-in Functions

One of the cleanest uses of map() is pairing it with Python's built-in functions. No lambda needed -- just pass the function name directly.

Converting Types with int, float, str

# Convert strings to integers
string_numbers = ["10", "20", "30", "40"]
integers = list(map(int, string_numbers))
print(integers)
# [10, 20, 30, 40]
 
# Convert integers to floats
values = [1, 2, 3, 4]
floats = list(map(float, values))
print(floats)
# [1.0, 2.0, 3.0, 4.0]
 
# Convert numbers to strings
ids = [101, 102, 103]
string_ids = list(map(str, ids))
print(string_ids)
# ['101', '102', '103']

Getting Lengths with len

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

Stripping Whitespace with str.strip

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

Other Useful Built-in Pairings

# abs() for absolute values
numbers = [-5, 3, -1, 7, -2]
absolutes = list(map(abs, numbers))
print(absolutes)
# [5, 3, 1, 7, 2]
 
# round() for rounding (single-argument form)
prices = [19.995, 4.123, 99.876]
rounded = list(map(round, prices))
print(rounded)
# [20, 4, 100]
 
# bool() for truthiness
values = [0, 1, "", "hello", None, [], [1]]
truthy = list(map(bool, values))
print(truthy)
# [False, True, False, True, False, False, True]

When a built-in function already does what you need, pass it directly to map(). There is no reason to wrap it in a lambda.

map() with Lambda Functions

Lambda functions unlock the full power of map(). They let you define inline transformations without creating a named function.

# Square each number
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x ** 2, numbers))
print(squared)
# [1, 4, 9, 16, 25]
 
# Celsius to Fahrenheit
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]
 
# Extract domain from email addresses
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']
 
# Format names
names = ["alice smith", "bob jones", "carol white"]
formatted = list(map(lambda n: n.title(), names))
print(formatted)
# ['Alice Smith', 'Bob Jones', 'Carol White']

The pattern is consistent: map(lambda x: transform(x), iterable). Keep the lambda body to a single, clear expression. If the transformation requires multiple steps, use a named function instead.

map() with Multiple Iterables

When you pass multiple iterables, map() calls the function with one element from each iterable in parallel. The function must accept as many arguments as there are iterables. Iteration stops when the shortest iterable is exhausted.

# Add corresponding elements from two lists
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]
 
# Calculate weighted scores
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]
 
# Combine first and last names
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']

Three or More Iterables

# Calculate volume from three dimension lists
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]

Handling Unequal Lengths

map() stops at the shortest iterable. No error, no padding -- it simply stops:

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]
# Elements 4 and 5 from 'a' are silently dropped

If you need to handle unequal lengths explicitly, use 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 List Comprehension

This is the comparison that matters most. Both map() and list comprehensions transform sequences, but they have different strengths.

Featuremap()List Comprehension
Syntaxmap(func, iterable)[func(x) for x in iterable]
Readability (simple transform)High with built-in functionsHigh for all cases
Readability (complex transform)Lower (nested lambdas)Higher (multi-line possible)
Filtering supportNo (needs filter() separately)Yes (if clause built in)
Return typeLazy iterator (map object)Eager list
Memory for large dataLow (lazy evaluation)High (full list in memory)
Speed (built-in function)Faster (no Python-level call)Slightly slower
Speed (lambda function)ComparableComparable or slightly faster
Nested transformsAwkward to chainNatural with nesting
DebuggingHarder (lazy, no intermediate list)Easier (immediate results)

Performance Benchmark

import timeit
 
data = list(range(100_000))
 
# map with built-in function
time_map_builtin = timeit.timeit(
    'list(map(str, data))',
    globals={'data': data},
    number=100
)
 
# List comprehension with built-in function
time_comp_builtin = timeit.timeit(
    '[str(x) for x in data]',
    globals={'data': data},
    number=100
)
 
# map with lambda
time_map_lambda = timeit.timeit(
    'list(map(lambda x: x * 2, data))',
    globals={'data': data},
    number=100
)
 
# List comprehension equivalent
time_comp_expr = timeit.timeit(
    '[x * 2 for x in data]',
    globals={'data': data},
    number=100
)
 
print(f"map + built-in:   {time_map_builtin:.4f}s")
print(f"comprehension:    {time_comp_builtin:.4f}s")
print(f"map + lambda:     {time_map_lambda:.4f}s")
print(f"comprehension:    {time_comp_expr:.4f}s")
# Typical results:
# map + built-in:   ~0.85s (faster)
# comprehension:    ~1.05s
# map + lambda:     ~0.95s
# comprehension:    ~0.80s (faster)

The key insight: map() with a built-in function (like int, str, float) is faster because it avoids creating a Python-level function call on each iteration. But map() with a lambda is roughly the same speed as -- or slightly slower than -- a list comprehension, because both involve a Python-level function call per element.

map() vs Generator Expression

If you do not need the full result list in memory, both map() and generator expressions provide lazy evaluation:

# map object - lazy
mapped = map(lambda x: x ** 2, range(1_000_000))
 
# Generator expression - lazy
generated = (x ** 2 for x in range(1_000_000))
 
# Both consume memory only as you iterate
for value in mapped:
    if value > 100:
        break

The difference is stylistic. Generator expressions read more naturally for most Python developers and support filtering with if clauses. Use map() when you already have a named function to apply; use a generator expression otherwise.

# map is clean when you have a named function
import math
roots = map(math.sqrt, range(10))
 
# Generator is clean for expressions
roots = (x ** 0.5 for x in range(10))

Converting map Objects to list, tuple, and set

The map object is an iterator. To materialize the results, convert it explicitly:

numbers = [1, 2, 3, 2, 4, 3, 5]
 
# To list (preserves order, allows duplicates)
as_list = list(map(lambda x: x * 10, numbers))
print(as_list)
# [10, 20, 30, 20, 40, 30, 50]
 
# To tuple (immutable sequence)
as_tuple = tuple(map(lambda x: x * 10, numbers))
print(as_tuple)
# (10, 20, 30, 20, 40, 30, 50)
 
# To set (removes duplicates, unordered)
as_set = set(map(lambda x: x * 10, numbers))
print(as_set)
# {10, 20, 30, 40, 50}

Important: A map object can only be consumed once. After you convert it to a list, iterating again yields nothing:

mapped = map(str, [1, 2, 3])
first = list(mapped)
second = list(mapped)
print(first)   # ['1', '2', '3']
print(second)  # [] -- already exhausted

map() with Custom Functions

For transformations that are too complex for a lambda, define a regular function and pass it to map():

def parse_temperature(reading):
    """Convert a temperature reading string to a standardized dict."""
    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"Unknown unit: {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

This pattern keeps map() calls clean while moving complex logic into testable, documented functions.

def normalize_record(record):
    """Standardize a user record for database insertion."""
    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}

Chaining map() Calls

Because map() returns an iterator, you can chain multiple map() calls to build transformation pipelines. Each step processes one element at a time without creating intermediate lists:

raw_data = ["  42  ", " 17 ", "  89  ", " 3  "]
 
# Chain: strip whitespace -> convert to int -> double the value
result = map(str.strip, raw_data)
result = map(int, result)
result = map(lambda x: x * 2, result)
 
print(list(result))
# [84, 34, 178, 6]

For readability, you can nest the calls (read inside-out):

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]

The nested version is compact but harder to read. The sequential version is clearer for multi-step pipelines. Neither creates intermediate lists -- all three map objects evaluate lazily.

map() in Data Processing Pipelines

Real-world data processing often involves reading, cleaning, transforming, and aggregating data. map() fits naturally into this pattern.

Processing Log Entries

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'}]

Batch File Renaming Logic

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']

Numerical Data Pipeline

import math
 
raw_measurements = ["3.14159", "2.71828", "1.41421", "1.73205"]
 
# Pipeline: parse -> square -> take log -> round to 3 decimals
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]

When to Use map() vs List Comprehension: A Decision Guide

Use this quick reference to decide which tool fits your situation:

Use map() when:

  • You are applying a single built-in function: map(int, strings), map(str.strip, lines)
  • You already have a named function that does the transformation
  • You want lazy evaluation and do not need the full list in memory
  • You are passing multiple iterables for element-wise operations

Use a list comprehension when:

  • The transformation is a simple expression: [x * 2 for x in numbers]
  • You need filtering in the same step: [x for x in items if x > 0]
  • The logic involves multiple conditions or nested operations
  • You want the result as a list immediately
  • Readability matters more than micro-optimization

Use a generator expression when:

  • You need lazy evaluation but want the readability of comprehension syntax
  • The result will be consumed only once (passed to sum(), max(), join(), etc.)
# map -- cleanest for type conversion
integers = list(map(int, ["1", "2", "3"]))
 
# List comprehension -- cleanest for transform + filter
even_squares = [x ** 2 for x in range(20) if x % 2 == 0]
 
# Generator expression -- cleanest for single-pass consumption
total = sum(x ** 2 for x in range(1000))

Experimenting with map() in RunCell

When you are building data transformation pipelines with map(), testing each stage interactively is essential. You need to see intermediate results, check edge cases, and verify that chained maps produce the expected output.

RunCell (opens in a new tab) is an AI agent that runs directly inside Jupyter notebooks. It understands your notebook context -- the variables, DataFrames, and imports already in memory -- and helps you build and debug map() pipelines step by step:

  • Visualize intermediate results. Ask RunCell to show what each stage of a chained map() produces, without breaking your pipeline.
  • Suggest vectorized alternatives. If you are using map() on pandas Series, RunCell can recommend native pandas operations that run 10-100x faster.
  • Convert between map and comprehension. Describe the transformation and RunCell generates both versions so you can pick the most readable one.
  • Debug edge cases. Feed unexpected input (None values, empty strings, mixed types) into your map pipeline and see exactly where it breaks.

FAQ

What does the map() function do in Python?

The map() function applies a given function to every item in one or more iterables (like lists, tuples, or strings) and returns an iterator of the results. It is a built-in function that enables functional-style data transformation without writing explicit loops. The syntax is map(function, iterable), and the returned map object is lazy -- it computes results on demand rather than all at once.

Is map() faster than a for loop in Python?

Yes, map() is generally faster than an equivalent for loop that builds a list with append(). The speed advantage comes from map() being implemented in C at the interpreter level, which avoids the overhead of Python-level loop iteration and method calls. When using map() with a built-in function like int or str, the performance gain is most significant -- typically 20-40% faster. With a lambda, the difference narrows because the lambda itself introduces a Python-level function call.

How do I convert a map object to a list?

Wrap the map() call with list(): result = list(map(int, strings)). You can also convert to other collections: tuple(map(...)) for tuples, set(map(...)) for sets. Remember that a map object is a single-use iterator. Once consumed (by converting to a list or iterating through it), it is exhausted and cannot be reused.

Can map() work with multiple lists?

Yes. Pass multiple iterables after the function: map(func, list1, list2, list3). The function must accept the same number of arguments as there are iterables. For example, list(map(lambda a, b: a + b, [1, 2], [10, 20])) returns [11, 22]. Iteration stops at the shortest iterable, so unequal-length lists do not raise errors -- extra elements are silently ignored.

Should I use map() or a list comprehension?

Use map() when applying a single existing function (built-in or named) to an iterable, especially for type conversions like map(int, strings). Use a list comprehension when the transformation involves an expression, when you need filtering with an if clause, or when readability is the priority. In modern Python, list comprehensions are the default choice for most developers, but map() with built-in functions remains faster and more concise for simple one-function transforms.

Conclusion

The Python map() function is a precise tool for a specific job: applying a single function to every element of an iterable without writing a loop. It excels when paired with built-in functions like int, str, float, and len, where it produces the most readable and fastest code. With lambda functions, it handles inline transformations cleanly. With multiple iterables, it processes element-wise operations that would otherwise require zip() and a loop.

Here are the rules for using map() effectively:

  • Pass built-in functions directly: map(int, strings) not map(lambda x: int(x), strings).
  • Use lambda only for simple, single-expression transforms.
  • Switch to a named function when the transformation needs error handling, multiple steps, or documentation.
  • Prefer list comprehensions when you need filtering or when the expression is clearer inline.
  • Remember that map() returns a lazy, single-use iterator -- convert to list() when you need to reuse or inspect results.
  • Chain map() calls for multi-step pipelines without creating intermediate lists.

map() is not a replacement for list comprehensions, and list comprehensions are not a replacement for map(). They overlap but serve different strengths. The best Python code uses each where it fits naturally: map() for applying existing functions, list comprehensions for expressions and filtering, and generator expressions for lazy single-pass consumption.

📚