Python Inbuilt Looping Functions: A Complete Guide
Python's nine built-in iteration helpers: range, enumerate, zip, map, filter, sorted, reversed, iter, and next, with code examples for placement coding rounds.
Python ships nine built-in iteration helpers beyond for and while: range, enumerate, zip, map, filter, reversed, sorted, iter, and next. The itertools and functools modules extend this set further. Placement coding rounds test these regularly, and knowing which to reach for saves time on timed assessments.
If you are new to Python programs in general, the Python basic programs guide covers I/O, conditionals, and control flow first.
Building loops with range()
range() has three signatures, all documented in the Python built-in functions reference:
range(stop)— integers from 0 up to (but not including) stoprange(start, stop)— integers from start up to (not including) stoprange(start, stop, step)— every step-th integer from start to stop
range() returns a range object (lazy), not a list. This matters for memory when iterating over large counts.
# 0 through 4
for i in range(5):
print(i)
# 2, 4, 6, 8, 10
for i in range(2, 11, 2):
print(i)
# Countdown: 10 down to 1
for i in range(10, 0, -1):
print(i)
# Convert to a list when you need it as data
print(list(range(5))) # [0, 1, 2, 3, 4]
A common placement question: “iterate over a list by index.” The pattern for i in range(len(lst)) works, but using enumerate() is cleaner in most cases (covered in the next section).
Iterating with structure: enumerate() and zip()
enumerate()
enumerate(iterable, start=0) adds a counter to any iterable, returning (index, value) tuples. No manual counter variable needed.
fruits = ["apple", "banana", "mango"]
# Default counter starts at 0
for i, fruit in enumerate(fruits):
print(i, fruit)
# 0 apple
# 1 banana
# 2 mango
# Start the counter at 1
for i, fruit in enumerate(fruits, start=1):
print(i, fruit)
# 1 apple
# 2 banana
# 3 mango
This replaces for i in range(len(fruits)) with something that is harder to get wrong and does not require the list length at all.
zip()
zip(*iterables) pairs elements from multiple iterables by position.
names = ["Ravi", "Priya", "Arjun"]
scores = [85, 92, 78]
for name, score in zip(names, scores):
print(f"{name}: {score}")
# Ravi: 85
# Priya: 92
# Arjun: 78
zip() stops when the shortest iterable ends. Python 3.10 added zip(*iterables, strict=False): set strict=True to raise ValueError when lengths differ.
dict.items()
For dictionaries, dict.items() returns (key, value) pairs and is the standard way to loop over both at once:
student = {"name": "Kavya", "score": 91, "branch": "CSE"}
for key, value in student.items():
print(key, "->", value)
Transforming and filtering: map() and filter()
map()
map(function, iterable) applies a function to every element and returns a lazy iterator.
# Convert a list of strings to integers
str_nums = ["10", "20", "30", "40"]
ints = list(map(int, str_nums))
print(ints) # [10, 20, 30, 40]
# Apply a lambda
doubles = list(map(lambda x: x * 2, [1, 2, 3, 4]))
print(doubles) # [2, 4, 6, 8]
Wrap map() in list() to materialise the output; it does not evaluate eagerly in Python 3.
filter()
filter(function, iterable) keeps elements where the function returns True.
nums = [1, 2, 3, 4, 5, 6, 7, 8]
evens = list(filter(lambda x: x % 2 == 0, nums))
print(evens) # [2, 4, 6, 8]
Both map() and filter() return lazy iterators. A list comprehension like [x * 2 for x in nums] or [x for x in nums if x % 2 == 0] is often more readable for inline expressions, but map() and filter() read cleanly when the function is already named elsewhere.
Ordering iteration: reversed() and sorted()
reversed()
reversed(sequence) returns an iterator over the sequence in reverse order, without modifying the original.
nums = [1, 2, 3, 4, 5]
for n in reversed(nums):
print(n)
# 5 4 3 2 1
print(nums) # [1, 2, 3, 4, 5] — original unchanged
reversed() requires a sequence (list, tuple, string) or an object with __reversed__. It does not work on arbitrary iterables like generators.
sorted()
sorted(iterable, key=None, reverse=False) returns a new sorted list. The original stays intact, unlike list.sort(), which sorts in place and returns None.
fruits = ["Banana", "Apple", "Mango", "Guava"]
print(sorted(fruits)) # ['Apple', 'Banana', 'Guava', 'Mango']
print(sorted(fruits, reverse=True)) # ['Mango', 'Guava', 'Banana', 'Apple']
print(fruits) # ['Banana', 'Apple', 'Mango', 'Guava'] — unchanged
Use the key parameter for custom ordering:
words = ["banana", "apple", "fig", "mango"]
print(sorted(words, key=len)) # ['fig', 'apple', 'mango', 'banana']
For sorting strings character by character, the alphabetical-order sorting guide shows the full placement-test context.
Going further: iter(), next(), and itertools
iter() and next()
iter(obj) converts a sequence or iterable into an iterator. next(iterator, default) retrieves the next element; the optional default prevents StopIteration when the iterator is exhausted.
nums = [10, 20, 30]
it = iter(nums)
print(next(it)) # 10
print(next(it)) # 20
print(next(it, "end")) # 30
print(next(it, "end")) # end (no StopIteration raised)
Manual iteration with iter() and next() is useful when you need to consume a few elements before entering a loop, or when processing streams one item at a time.
itertools highlights
The Python itertools module ships 18 tools for iterator algebra. Three that appear regularly in placement and interview questions:
import itertools
# chain — iterate over multiple iterables in sequence
for x in itertools.chain([1, 2], [3, 4], [5]):
print(x) # 1 2 3 4 5
# islice — take the first n elements from any iterator (lazy)
for x in itertools.islice(range(1000), 5):
print(x) # 0 1 2 3 4
# groupby — group consecutive elements sharing the same key
data = [("A", 1), ("A", 2), ("B", 3), ("B", 4)]
for key, group in itertools.groupby(data, key=lambda x: x[0]):
print(key, list(group))
# A [('A', 1), ('A', 2)]
# B [('B', 3), ('B', 4)]
groupby() requires the data to be sorted by the key first; if it is not sorted, you get one group per consecutive run, not one group per unique key value.
Accumulating with functools.reduce()
functools.reduce(function, iterable, initializer) applies a binary function cumulatively, reducing a sequence to a single value.
from functools import reduce
nums = [1, 2, 3, 4, 5]
total = reduce(lambda a, b: a + b, nums)
print(total) # 15
product = reduce(lambda a, b: a * b, nums)
print(product) # 120
For summing, sum(nums) is faster because it is implemented in C. Use reduce() when the accumulating operation has no built-in equivalent. The sum of array guide compares sum(), a manual loop, and reduce() side by side, which is the comparison format placement tests tend to ask for.
Quick reference: which helper to use when
| Helper | Returns | Modifies original | Typical use |
|---|---|---|---|
range() | range object | N/A | Counting, index-based loops |
enumerate() | enumerate object | No | Index and value together |
zip() | zip object | No | Parallel iteration over two lists |
map() | map object | No | Apply a function to every element |
filter() | filter object | No | Keep elements matching a condition |
reversed() | iterator | No | Reverse order, original intact |
sorted() | new list | No | Sorted copy, works on any iterable |
iter() + next() | iterator + element | No | Manual, fine-grained iteration |
reduce() | single value | No | Custom accumulation |
The map() and filter() patterns in this table transfer directly to processing API outputs: filtering a list of model responses by score threshold, or mapping raw token IDs to labels, uses the same operations on different data. TinkerLLM applies these patterns in exercises built around real LLM outputs, starting at ₹299 for the first month.
Primary sources
Frequently asked questions
What is the difference between range() and enumerate() in Python?
range() generates a sequence of numbers for counting loops. enumerate() wraps any iterable and returns (index, value) tuples, so you get both position and element in each iteration. They solve different problems: range() when you need a counter, enumerate() when you need an index alongside the actual data.
Does zip() stop at the shorter list in Python?
Yes. zip() stops as soon as the shortest iterable is exhausted and silently drops the remaining elements of the longer one. Python 3.10 added a strict=True parameter that raises ValueError if the iterables have different lengths, which is useful when mismatched lengths indicate a data error.
What does map() return in Python 3?
map() returns a map object, which is a lazy iterator. It does not produce a list automatically. Wrap it in list() to get a list: list(map(int, str_nums)). This lazy behaviour saves memory when you only need to iterate once.
When should I use filter() instead of a list comprehension?
filter() with a named function reads cleanly when the filtering logic is already defined as a function (filter(is_prime, nums)). A list comprehension is more readable for inline conditions ([x for x in nums if x > 0]). Both produce equivalent results; the choice is stylistic. Placement tests accept either.
How is sorted() different from list.sort() in Python?
sorted() returns a new sorted list and works on any iterable (including tuples and generators). list.sort() sorts the list in place and returns None, and it only works on lists. Use sorted() when you need the original unchanged or when the input is not a list.
What is functools.reduce() used for in Python?
reduce() applies a binary function cumulatively across a sequence to produce a single value. sum(lst) is equivalent to reduce(lambda a, b: a + b, lst) but faster because sum() is implemented in C. Use reduce() when the accumulating operation is custom and has no equivalent built-in.
A self-paced playground for building with LLMs.
TinkerLLM is FACE Prep's sister property. A guided environment for shipping real LLM applications, the kind of project that earns a paragraph on your resume, not a line.
Try TinkerLLM (₹299 launch)