Python
Shuffling
List Manipulation
Python Programming
Coding Tutorial

Specific shuffling list in Python

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

Python's random.shuffle() randomizes a list in place, but many real-world scenarios require specific shuffling patterns — reproducible shuffles with a seed, shuffling without modifying the original, shuffling groups of elements together, or interleaving lists in a specific pattern. This article covers standard shuffling, seeded shuffles, partial shuffles, group-preserving shuffles, and custom shuffle algorithms.

Basic Shuffle (In-Place)

python
1import random
2
3items = [1, 2, 3, 4, 5]
4random.shuffle(items)
5print(items)  # e.g., [3, 1, 5, 2, 4] — different each run

random.shuffle() modifies the list in place and returns None. It uses the Fisher-Yates algorithm, which produces a uniform distribution of all permutations.

Shuffle Without Modifying the Original

Use random.sample() to get a shuffled copy:

python
1original = [1, 2, 3, 4, 5]
2shuffled = random.sample(original, len(original))
3
4print(original)  # [1, 2, 3, 4, 5] — unchanged
5print(shuffled)   # e.g., [4, 2, 5, 1, 3]

Or copy first, then shuffle:

python
shuffled = original.copy()
random.shuffle(shuffled)

Reproducible Shuffle (Seeded)

Set a seed so the shuffle produces the same result every time:

python
1random.seed(42)
2items = [1, 2, 3, 4, 5]
3random.shuffle(items)
4print(items)  # Always [1, 4, 2, 5, 3] with seed 42
5
6# Reset and shuffle again — same result
7random.seed(42)
8items = [1, 2, 3, 4, 5]
9random.shuffle(items)
10print(items)  # [1, 4, 2, 5, 3] again

Useful for testing, reproducible experiments, and debugging.

Shuffle with Custom Random Generator

Use an independent Random instance to avoid affecting global state:

python
1rng = random.Random(42)
2items = [1, 2, 3, 4, 5]
3rng.shuffle(items)
4print(items)  # Deterministic, independent of other random calls

This is important in multithreaded code or when you need multiple independent random streams.

Partial Shuffle (Shuffle First N Elements Only)

Shuffle only a portion of the list:

python
1def partial_shuffle(lst, n):
2    """Shuffle only the first n elements."""
3    subset = lst[:n]
4    random.shuffle(subset)
5    return subset + lst[n:]
6
7items = [1, 2, 3, 4, 5, 6, 7, 8]
8result = partial_shuffle(items, 4)
9print(result)  # e.g., [3, 1, 4, 2, 5, 6, 7, 8] — last 4 unchanged

Group-Preserving Shuffle

Shuffle groups of elements together (e.g., keep pairs intact):

python
1def shuffle_groups(lst, group_size):
2    """Shuffle list in chunks of group_size."""
3    groups = [lst[i:i + group_size] for i in range(0, len(lst), group_size)]
4    random.shuffle(groups)
5    return [item for group in groups for item in group]
6
7items = [1, 2, 3, 4, 5, 6]
8result = shuffle_groups(items, 2)
9print(result)  # e.g., [5, 6, 1, 2, 3, 4] — pairs stay together

Constrained Shuffle (No Element in Original Position)

A derangement ensures no element remains in its original position:

python
1def derangement(lst):
2    """Shuffle such that no element stays in its original position."""
3    result = lst.copy()
4    while True:
5        random.shuffle(result)
6        if all(result[i] != lst[i] for i in range(len(lst))):
7            return result
8
9items = [1, 2, 3, 4, 5]
10result = derangement(items)
11print(result)  # No element at its original index

This brute-force approach is efficient for small lists. For large lists, use the Sattolo algorithm.

Weighted Shuffle

Shuffle with bias — elements with higher weights appear earlier:

python
1items = ["A", "B", "C", "D"]
2weights = [10, 1, 5, 3]
3
4# Weighted shuffle using random.choices (with replacement) or sorted approach
5weighted_order = sorted(
6    range(len(items)),
7    key=lambda i: -random.random() ** (1.0 / weights[i])
8)
9result = [items[i] for i in weighted_order]
10print(result)  # "A" tends to appear first due to highest weight

Interleave Two Lists

Merge two lists in alternating order (a specific "shuffle" pattern):

python
1def interleave(a, b):
2    """Alternate elements from two lists."""
3    result = []
4    for x, y in zip(a, b):
5        result.extend([x, y])
6    # Append remaining elements from the longer list
7    result.extend(a[len(b):])
8    result.extend(b[len(a):])
9    return result
10
11list_a = [1, 2, 3]
12list_b = ["a", "b", "c"]
13print(interleave(list_a, list_b))  # [1, 'a', 2, 'b', 3, 'c']

Shuffle a Dictionary's Values

Shuffle values while keeping keys intact:

python
1d = {"a": 1, "b": 2, "c": 3, "d": 4}
2
3keys = list(d.keys())
4values = list(d.values())
5random.shuffle(values)
6
7shuffled_dict = dict(zip(keys, values))
8print(shuffled_dict)  # e.g., {'a': 3, 'b': 1, 'c': 4, 'd': 2}

Common Pitfalls

  • Assigning the return value of shuffle(): random.shuffle() returns None and modifies the list in place. result = random.shuffle(items) sets result to None. Use random.sample(items, len(items)) for a returned shuffled copy.
  • Shuffling immutable sequences: random.shuffle() requires a mutable sequence. Passing a tuple or string raises TypeError. Convert to a list first: list("hello"), then shuffle.
  • Global seed affecting other random calls: random.seed(42) affects all subsequent calls to the random module. Use random.Random(42) for an independent generator that does not interfere with other random operations.
  • Shuffling a generator: random.shuffle() needs indexed access (__getitem__). Generators and iterators do not support this. Convert to a list first: items = list(generator).
  • Non-uniform shuffle from a bad algorithm: Implementing shuffle manually (e.g., swapping each element with a random position from the entire array) produces a biased distribution. Always use Fisher-Yates (which random.shuffle implements) or random.sample().

Summary

  • random.shuffle(lst) shuffles in place (returns None) using the Fisher-Yates algorithm
  • random.sample(lst, len(lst)) returns a new shuffled list without modifying the original
  • Use random.seed(n) or random.Random(n) for reproducible shuffles
  • Chunk the list for group-preserving shuffles, or loop until a derangement for constrained shuffles
  • Use weighted random keys for priority-biased shuffling
  • Always use random.shuffle() or random.sample() instead of custom swap algorithms to ensure uniform distribution

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.