Skip to content

How to Print All Sublists of a List in Python

Learn how to generate all subsets (combinations) or contiguous sublists of a Python list using itertools, recursion, bit manipulation, or slicing.

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]

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.

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 [[]]

    remaining_subsets = get_subsets(a, index + 1)

    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.

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 = []

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]

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]

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

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 = [list(c) for r in range(len(a) + 1) for c in combinations(a, r)]
print("With empty:", all_subsets)

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

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

Comparison of Methods

Method Produces Includes Non-Contiguous Count Formula Time Complexity
itertools.combinations All subsets ✅ Yes 2ⁿ O(2ⁿ)
Recursion All subsets ✅ Yes 2ⁿ O(2ⁿ)
Bit manipulation All subsets ✅ Yes 2ⁿ O(n × 2ⁿ)
Slicing (comprehension) Contiguous only ❌ No n(n+1)/2 O(n²)
Nested loops Contiguous only ❌ No n(n+1)/2 O(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.
Navigation