Gyaan

Map, Filter, Reduce, Zip

intermediate map filter reduce zip functional

Python has a handful of functional programming tools that let us transform and combine data without writing explicit loops. They take a function and an iterable, and produce a new iterable.

map() — Transform Every Item

map() applies a function to each item in an iterable. It returns a lazy iterator (not a list), so we wrap it in list() when we need the result.

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

# Square each number
squared = list(map(lambda x: x ** 2, nums))
# [1, 4, 9, 16, 25]

# Convert strings to ints
str_nums = ["10", "20", "30"]
int_nums = list(map(int, str_nums))
# [10, 20, 30]

# map with multiple iterables
a = [1, 2, 3]
b = [10, 20, 30]
sums = list(map(lambda x, y: x + y, a, b))
# [11, 22, 33]

filter() — Keep Items That Pass a Test

filter() keeps only the items where the function returns a truthy value.

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

# Keep even numbers
evens = list(filter(lambda x: x % 2 == 0, nums))
# [2, 4, 6, 8]

# Remove empty strings
words = ["hello", "", "world", "", "python"]
non_empty = list(filter(None, words))  # None removes falsy values
# ['hello', 'world', 'python']

Passing None as the function is a neat trick — it filters out all falsy values.

reduce() — Combine All Items Into One

reduce() isn’t a built-in — we need to import it from functools. It takes the first two items, applies the function, then takes that result with the next item, and so on until there’s a single value left.

from functools import reduce

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

# Sum all numbers (1+2=3, 3+3=6, 6+4=10, 10+5=15)
total = reduce(lambda acc, x: acc + x, nums)
# 15

# Find the max value
biggest = reduce(lambda a, b: a if a > b else b, nums)
# 5

# Flatten a list of lists
nested = [[1, 2], [3, 4], [5, 6]]
flat = reduce(lambda a, b: a + b, nested)
# [1, 2, 3, 4, 5, 6]

Honestly, most of the time we’re better off using sum(), max(), or a loop instead of reduce(). It’s powerful but can be hard to read.

zip() — Combine Iterables in Parallel

zip() takes multiple iterables and pairs up their elements. It stops at the shortest iterable.

names = ["Alice", "Bob", "Charlie"]
scores = [90, 85, 92]

# Pair them up
pairs = list(zip(names, scores))
# [('Alice', 90), ('Bob', 85), ('Charlie', 92)]

# Super useful with dict()
score_map = dict(zip(names, scores))
# {'Alice': 90, 'Bob': 85, 'Charlie': 92}

# Unzip with *
pairs = [("a", 1), ("b", 2), ("c", 3)]
letters, numbers = zip(*pairs)
# letters = ('a', 'b', 'c'), numbers = (1, 2, 3)

If we need to handle iterables of different lengths without truncating, we use zip_longest from itertools.

from itertools import zip_longest

a = [1, 2, 3]
b = ["x", "y"]

list(zip_longest(a, b, fillvalue="-"))
# [(1, 'x'), (2, 'y'), (3, '-')]

enumerate() — Get Index + Value

Not exactly functional programming, but it pairs perfectly with these tools. It gives us the index and value while iterating.

fruits = ["apple", "banana", "cherry"]
for i, fruit in enumerate(fruits):
    print(f"{i}: {fruit}")
# 0: apple
# 1: banana
# 2: cherry

# Start from a different index
for i, fruit in enumerate(fruits, start=1):
    print(f"{i}: {fruit}")

Comprehensions vs map/filter

In most cases, comprehensions are more Pythonic and readable.

# These are equivalent
list(map(lambda x: x ** 2, nums))   # map style
[x ** 2 for x in nums]              # comprehension — cleaner

list(filter(lambda x: x > 3, nums)) # filter style
[x for x in nums if x > 3]          # comprehension — cleaner

In simple language, map transforms, filter selects, reduce combines, and zip pairs up. But if we can write it as a comprehension, that’s usually the more Pythonic choice.