Skip to main content

How to Print All Sublists of a List in Python

Generating all sublists (also called subsets or subsequences) of a list is a fundamental operation in combinatorics, algorithm design, and data analysis. Whether you need contiguous sublists (consecutive slices) or all possible subsets (including non-contiguous combinations), Python provides several approaches to accomplish this.

In this guide, you will learn multiple methods to generate sublists, understand the difference between contiguous sublists and all subsets, and choose the right approach based on your specific needs.

Understanding the Difference: Sublists vs. Subsets

Before diving into methods, it's important to distinguish between two related but different concepts:

Contiguous sublists (subarrays): consecutive elements from the original list:

[1, 2, 3] → [1], [2], [3], [1, 2], [2, 3], [1, 2, 3]

All subsets (subsequences): any combination of elements, maintaining order:

[1, 2, 3] → [], [1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]

Notice that [1, 3] is a subset but not a contiguous sublist because 1 and 3 are not adjacent in the original list.

Generating All Subsets

The most efficient and Pythonic way to generate all subsets uses itertools.combinations for each possible subset length:

from itertools import combinations

a = [1, 2, 3]

# Generate subsets of all lengths (0 to len(a))
subsets = []
for r in range(len(a) + 1):
for combo in combinations(a, r):
subsets.append(list(combo))

print(subsets)

Output:

[[], [1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]

Or as a compact one-liner:

from itertools import combinations

a = [1, 2, 3]

subsets = [list(combo) for r in range(len(a) + 1) for combo in combinations(a, r)]

print(subsets)

Output:

[[], [1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]

How it works:

  1. range(len(a) + 1) generates lengths from 0 (empty subset) to len(a) (full list).
  2. combinations(a, r) produces all subsets of length r, maintaining element order.
  3. The nested comprehension collects all subsets into a single flat list.
tip

This is the recommended approach for generating all subsets. itertools.combinations is implemented in C, making it significantly faster than pure-Python alternatives. It also naturally maintains the original order of elements.

Method 2: Using Recursion

A recursive approach builds subsets by deciding for each element whether to include it or not:

def get_subsets(a, index=0):
"""Generate all subsets recursively."""
if index == len(a):
return [[]]

# Get all subsets of the remaining elements
remaining_subsets = get_subsets(a, index + 1)

# Include current element in each subset, plus subsets without it
with_current = [[a[index]] + subset for subset in remaining_subsets]

return with_current + remaining_subsets


a = [1, 2, 3]
subsets = get_subsets(a)

print(f"Total subsets: {len(subsets)}")
print(subsets)

Output:

Total subsets: 8
[[1, 2, 3], [1, 2], [1, 3], [1], [2, 3], [2], [3], []]

How it works:

  1. Base case: When the index reaches the end of the list, return [[]] (only the empty subset).
  2. Recursive step: Get all subsets of the remaining elements, then create new subsets by prepending the current element to each.
  3. Return both: subsets with and without the current element.
info

For a list of n elements, there are exactly 2ⁿ subsets. For [1, 2, 3], that's 2³ = 8 subsets (including the empty set). This grows exponentially, so be cautious with large lists.

Method 3: Using Bit Manipulation

Each subset can be represented as a binary number where each bit indicates whether the corresponding element is included:

a = [1, 2, 3]

n = len(a)
subsets = []

# Each number from 0 to 2^n - 1 represents a subset
for i in range(2 ** n):
subset = [a[j] for j in range(n) if i & (1 << j)]
subsets.append(subset)

print(f"Total subsets: {len(subsets)}")
print(subsets)

Output:

Total subsets: 8
[[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]

How it works:

  • For [1, 2, 3], binary 101 (decimal 5) means include elements at index 0 and 2: [1, 3].
  • i & (1 << j) checks if bit j is set in number i.
  • Iterating from 0 to 2ⁿ - 1 covers all possible combinations.

Generating Contiguous Sublists Only

Method 4: Using List Comprehension

For contiguous sublists (consecutive slices), nested iteration over start and end indices is the cleanest approach:

a = [1, 2, 3]

sublists = [a[i:j] for i in range(len(a)) for j in range(i + 1, len(a) + 1)]

print(sublists)

Output:

[[1], [1, 2], [1, 2, 3], [2], [2, 3], [3]]

Method 5: Using Nested Loops

The explicit loop version for clarity:

a = [1, 2, 3]

sublists = []
for i in range(len(a)):
for j in range(i + 1, len(a) + 1):
sublists.append(a[i:j])

print(f"Total contiguous sublists: {len(sublists)}")
for sub in sublists:
print(f" {sub}")

Output:

Total contiguous sublists: 6
[1]
[1, 2]
[1, 2, 3]
[2]
[2, 3]
[3]
info

For a list of n elements, there are exactly n × (n + 1) / 2 contiguous sublists. For [1, 2, 3], that's 3 × 4 / 2 = 6. This grows quadratically, which is much more manageable than the exponential growth of all subsets.

Common Mistake: Confusing Contiguous Sublists with All Subsets

A frequent error is using the slicing approach and expecting it to produce all subsets:

Wrong expectation:

a = [1, 2, 3]

# This only produces CONTIGUOUS sublists
sublists = [a[i:j] for i in range(len(a)) for j in range(i + 1, len(a) + 1)]
print([1, 3] in sublists) # False ([1, 3] is NOT contiguous)

Output:

False
note

[1, 3] is a valid subset but not a contiguous sublist. If you need all subsets including non-contiguous ones, use itertools.combinations or recursion.

Including the Empty Sublist

Some applications require the empty sublist []. Here's how to include it with each method:

from itertools import combinations

a = [1, 2, 3]

# All subsets including empty (start range from 0)
all_subsets = [list(c) for r in range(len(a) + 1) for c in combinations(a, r)]
print("With empty:", all_subsets)

# Without empty (start range from 1)
non_empty = [list(c) for r in range(1, len(a) + 1) for c in combinations(a, r)]
print("Without empty:", non_empty)

Output:

With empty: [[], [1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]
Without empty: [[1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]

Performance Considerations

# Number of results for different list sizes
for n in [3, 5, 10, 15, 20]:
contiguous = n * (n + 1) // 2
all_subsets = 2 ** n
print(f"n={n:2d}: Contiguous sublists={contiguous:>6,} | All subsets={all_subsets:>10,}")

Output:

n= 3: Contiguous sublists=     6  |  All subsets=         8
n= 5: Contiguous sublists= 15 | All subsets= 32
n=10: Contiguous sublists= 55 | All subsets= 1,024
n=15: Contiguous sublists= 120 | All subsets= 32,768
n=20: Contiguous sublists= 210 | All subsets= 1,048,576
caution

Generating all subsets has exponential time and space complexity (O(2ⁿ)). For a list of 20 elements, that's over 1 million subsets. For 30 elements, it's over 1 billion. Only generate all subsets for small lists (typically n ≤ 20).

Comparison of Methods

MethodProducesIncludes Non-ContiguousCount FormulaTime Complexity
itertools.combinationsAll subsets✅ Yes2ⁿO(2ⁿ)
RecursionAll subsets✅ Yes2ⁿO(2ⁿ)
Bit manipulationAll subsets✅ Yes2ⁿO(n × 2ⁿ)
Slicing (comprehension)Contiguous only❌ Non(n+1)/2O(n²)
Nested loopsContiguous only❌ Non(n+1)/2O(n²)

Summary

Generating sublists in Python depends on whether you need contiguous slices or all possible subsets:

  • For all subsets (including non-contiguous): Use itertools.combinations: the fastest, most Pythonic approach.
  • For contiguous sublists only: Use list comprehension with slicing: clean and efficient.
  • For educational purposes or custom logic: Use recursion or bit manipulation to understand the underlying algorithms.

Key reminders:

  • All subsets grow exponentially (2ⁿ): be cautious with large lists.
  • Contiguous sublists grow quadratically (n²): much more manageable.
  • Use range(len(a) + 1) to include the empty subset, or range(1, len(a) + 1) to exclude it.
  • Don't confuse contiguous sublists with all subsets: they produce different results.