Functional Programming
List comprehensions, map/filter/reduce, lambda vs Java Stream API
Introduction
In this lesson, you'll learn about functional programming in Python. Coming from Java, you already have a foundation for understanding this concept. We'll build on that knowledge while highlighting the key differences.
In Java, you're familiar with list comprehensions, map/filter/reduce, lambda vs java stream api.
Python has its own approach to list comprehensions, map/filter/reduce, lambda vs java stream api, which we'll explore step by step.
The Python Way
Let's see how Python handles this concept. Here's a typical example:
from functools import reduce
nums = [1, 2, 3, 4, 5, 6]
# List comprehension (most Pythonic)
even_squares = [x**2 for x in nums if x % 2 == 0]
# [4, 16, 36]
# Dict comprehension
squared_map = {x: x**2 for x in nums}
# {1:1, 2:4, 3:9, ...}
# Set comprehension
unique_mods = {x % 3 for x in nums}
# {0, 1, 2}
# Generator expression (lazy — like Java streams)
gen = (x**2 for x in nums if x % 2 == 0)
# map / filter (functional style — less Pythonic)
even = list(filter(lambda x: x % 2 == 0, nums))
squares = list(map(lambda x: x**2, nums))
# reduce
total = reduce(lambda a, b: a + b, nums, 0) # 21
# OR: sum(nums)
# groupby (itertools)
from itertools import groupby
sorted_nums = sorted(nums, key=lambda x: x % 2)
grouped = {k: list(v) for k, v in groupby(sorted_nums, key=lambda x: x%2)}
# flatten
nested = [[1,2],[3,4]]
flat = [x for sublist in nested for x in sublist]
# [1, 2, 3, 4]Comparing to Java
Here's how you might have written similar code in Java:
import java.util.*;
import java.util.stream.*;
List<Integer> nums = List.of(1, 2, 3, 4, 5, 6);
// filter + map + collect
List<Integer> evenSquares = nums.stream()
.filter(x -> x % 2 == 0)
.map(x -> x * x)
.collect(Collectors.toList());
// [4, 16, 36]
// reduce
int sum = nums.stream()
.reduce(0, Integer::sum); // 21
// groupingBy
Map<String, List<Integer>> grouped = nums.stream()
.collect(Collectors.groupingBy(
n -> n % 2 == 0 ? "even" : "odd"));
// flatMap
List<List<Integer>> nested = List.of(List.of(1,2), List.of(3,4));
List<Integer> flat = nested.stream()
.flatMap(Collection::stream)
.collect(Collectors.toList());
// sorted + distinct
List<Integer> sorted = nums.stream()
.sorted()
.distinct()
.collect(Collectors.toList());You may be used to different syntax or behavior.
List comprehensions are preferred over map/filter in Python — more readable
You may be used to different syntax or behavior.
Python comprehensions are eagerly evaluated; Java streams are lazy
You may be used to different syntax or behavior.
Generator expressions are lazy like Java streams: (x**2 for x in ...)
You may be used to different syntax or behavior.
Python's itertools.groupby requires pre-sorting; Java's Collectors.groupingBy does not
You may be used to different syntax or behavior.
sum()/min()/max() are built-in Python functions; Java uses mapToInt().sum()
Step-by-Step Breakdown
1. List Comprehensions
List comprehensions are the Pythonic way to filter and transform collections. More readable than map/filter for most cases.
nums.stream().filter(x->x%2==0).map(x->x*x).collect(toList())[x**2 for x in nums if x % 2 == 0]2. Dict and Set Comprehensions
Python has dict and set comprehensions too — no Java equivalent for these concise forms.
// Java: Collectors.toMap(k->k, v->v*v){x: x**2 for x in nums} # dict comprehension
{x % 3 for x in nums} # set comprehension3. Generator Expressions (Lazy)
Generator expressions are lazy like Java streams. They produce values on demand without creating the full list in memory.
nums.stream().filter(x->x>3) // lazy streamgen = (x**2 for x in nums) # generator — lazy
next(gen) # get one value
sum(gen) # consume rest4. Functional Tools
map/filter/reduce exist in Python but are less commonly used than comprehensions. reduce is in functools (not built-in).
nums.stream().reduce(0, Integer::sum)
nums.stream().filter(x->x>0).count()from functools import reduce
reduce(lambda a,b: a+b, nums, 0) # sum
sum(x for x in nums if x > 0) # more Pythonic
len([x for x in nums if x > 0]) # countCommon Mistakes
When coming from Java, developers often make these mistakes:
- List comprehensions are preferred over map/filter in Python — more readable
- Python comprehensions are eagerly evaluated; Java streams are lazy
- Generator expressions are lazy like Java streams: (x**2 for x in ...)
Key Takeaways
- List comprehensions [expr for x in iter if cond] are preferred over map/filter
- Dict {k:v for k,v in ...} and set {x for x in ...} comprehensions are also available
- Generator expressions (x**2 for x in iter) are lazy — like Java streams
- sum()/min()/max() are built-in; reduce() is in functools