itertools & functools
itertools: lazy iteration without dependencies
Section titled “itertools: lazy iteration without dependencies”TypeScript developers often reach for Lodash for collection utilities. Python ships itertools in the standard library, and it is lazy — it produces values on demand without building intermediate lists. This matters for large datasets.
chain — flatten multiple iterables
Section titled “chain — flatten multiple iterables”// TypeScript / Lodashimport _ from 'lodash';const result = _.concat([1, 2], [3, 4], [5]);// or spread:const result2 = [...[1, 2], ...[3, 4], ...[5]];console.log(result); // [1, 2, 3, 4, 5]import itertools
result = list(itertools.chain([1, 2], [3, 4], [5]))print(result) # [1, 2, 3, 4, 5]
# chain.from_iterable — flatten one level of nestingnested = [[1, 2], [3, 4], [5]]flat = list(itertools.chain.from_iterable(nested))print(flat) # [1, 2, 3, 4, 5]count — infinite counter
Section titled “count — infinite counter”// TypeScript — manual counter or generatorfunction* count(start = 0, step = 1) { let n = start; while (true) { yield n; n += step; }}
const gen = count(10, 2);const result = Array.from({ length: 4 }, () => gen.next().value);console.log(result); // [10, 12, 14, 16]import itertools
counter = itertools.count(10, 2) # infinite lazy counterresult = [next(counter) for _ in range(4)]print(result) # [10, 12, 14, 16]
# islice — safely take N items from an infinite iteratorfirst_five = list(itertools.islice(itertools.count(1), 5))print(first_five) # [1, 2, 3, 4, 5]groupby — group consecutive items
Section titled “groupby — group consecutive items”groupby is like SQL GROUP BY but it requires sorted input — it groups consecutive equal keys.
// TypeScript / Lodashimport _ from 'lodash';const data = [ { cat: "a", val: 1 }, { cat: "a", val: 2 }, { cat: "b", val: 3 }, { cat: "b", val: 4 },];const grouped = _.groupBy(data, "cat");// { a: [...], b: [...] }import itertools
data = [("a", 1), ("a", 2), ("b", 3), ("b", 4)]# Input must be sorted by key first!for key, group in itertools.groupby(data, key=lambda x: x[0]): items = list(group) print(f"{key}: {items}")# a: [('a', 1), ('a', 2)]# b: [('b', 3), ('b', 4)]functools: higher-order functions
Section titled “functools: higher-order functions”reduce
Section titled “reduce”// TypeScriptconst sum = [1, 2, 3, 4, 5].reduce((acc, x) => acc + x, 0);console.log(sum); // 15import functools
result = functools.reduce(lambda acc, x: acc + x, [1, 2, 3, 4, 5])print(result) # 15
# With initial valueresult2 = functools.reduce(lambda acc, x: acc + x, [1, 2, 3], 100)print(result2) # 106lru_cache — memoization
Section titled “lru_cache — memoization”@lru_cache is Python’s built-in memoization decorator. The equivalent in TypeScript is a manual Map-based cache or a library like memoize-one.
// TypeScript — manual memoizationconst memo = new Map<number, number>();
function fib(n: number): number { if (n < 2) return n; if (memo.has(n)) return memo.get(n)!; const result = fib(n - 1) + fib(n - 2); memo.set(n, result); return result;}
console.log(fib(30)); // 832040import functools
@functools.lru_cache(maxsize=128)def fib(n: int) -> int: if n < 2: return n return fib(n - 1) + fib(n - 2)
print(fib(30)) # 832040print(fib.cache_info()) # hits=28, misses=31, ...partial — pre-fill arguments
Section titled “partial — pre-fill arguments”// TypeScript — bind or arrow wrapperfunction multiply(a: number, b: number): number { return a * b;}
const double = multiply.bind(null, 2);// or: const double = (b: number) => multiply(2, b);
console.log(double(5)); // 10console.log(double(10)); // 20import functools
def multiply(a: int, b: int) -> int: return a * b
double = functools.partial(multiply, 2)print(double(5)) # 10print(double(10)) # 20
# partial also works with keyword argumentsdef connect(host: str, port: int, ssl: bool = False) -> str: return f"{'https' if ssl else 'http'}://{host}:{port}"
prod = functools.partial(connect, port=443, ssl=True)print(prod("api.example.com")) # https://api.example.com:443Try it
Section titled “Try it”import itertoolsimport functools
# chainmerged = list(itertools.chain([1, 2], [3, 4], [5]))print("chain:", merged)
# islice from countfirst_six = list(itertools.islice(itertools.count(0, 10), 6))print("count+islice:", first_six)
# groupbywords = ["apple", "ant", "bear", "banana", "cat"]words.sort(key=lambda w: w[0]) # must sort first!for letter, group in itertools.groupby(words, key=lambda w: w[0]): print(f" {letter}: {list(group)}")
# lru_cache fibonacci@functools.lru_cache(maxsize=64)def fib(n: int) -> int: if n < 2: return n return fib(n - 1) + fib(n - 2)
print("fib(20):", fib(20))print("cache:", fib.cache_info())
# partialdef power(base: int, exp: int) -> int: return base ** exp
square = functools.partial(power, exp=2)cube = functools.partial(power, exp=3)print("squares:", [square(x) for x in range(1, 6)])print("cubes :", [cube(x) for x in range(1, 6)])Loading Python runtime (first run only)…