Random.shuffle: примеры (PYTHON)

Использование random.shuffle для перемешивания последовательностей в Python
Раздел: Случайные числа, Перемешивание
random.shuffle(x: mutable sequence, random: random.Random=None): None

Функция random.shuffle: основы и параметры

Функция random.shuffle() из модуля random в Python предназначена для перемешивания изменяемых последовательностей на месте. Её основное применение – случайное изменение порядка элементов в списках, что полезно в задачах рандомизации, статистического моделирования, игровых механиках и машинном обучении.

Сигнатура функции:

random.shuffle(x, random=None)

Аргументы:

  • x (MutableSequence) – обязательный аргумент, изменяемая последовательность (обычно список). Функция изменяет эту последовательность непосредственно, не создавая новую.
  • random (callable, optional) – необязательный аргумент, функция, возвращающая случайные числа в диапазоне [0.0, 1.0). По умолчанию используется функция random.random() из того же модуля.

Возвращаемое значение:

Функция не возвращает значения (возвращает None), так как работает непосредственно с переданной последовательностью.

Особенности работы:

  • Для неизменяемых последовательностей (кортежи, строки) использовать нельзя – необходимо преобразовать в список.
  • Для многомерных структур (например, списка списков) перемешиваются только элементы первого уровня.
  • При использовании пользовательской функции random алгоритм перемешивания остается тем же, но источник случайности изменяется.

Базовые примеры использования

Пример 1: Перемешивание простого списка

import random
numbers = [1, 2, 3, 4, 5]
random.shuffle(numbers)
print(numbers)
[3, 5, 1, 4, 2]  # Результат будет разным при каждом запуске

Пример 2: Перемешивание списка строк

import random
words = ['яблоко', 'банан', 'вишня', 'дата']
random.shuffle(words)
print(words)
['банан', 'дата', 'вишня', 'яблоко']

Пример 3: Использование пользовательского генератора случайных чисел

import random
import time

def my_random():
    return (time.time_ns() % 100) / 100.0

items = ['A', 'B', 'C', 'D', 'E']
random.shuffle(items, my_random)
print(items)
['C', 'A', 'E', 'D', 'B']

Пример 4: Перемешивание вложенных структур

import random
matrix = [[1, 2], [3, 4], [5, 6]]
random.shuffle(matrix)
print(matrix)
[[5, 6], [1, 2], [3, 4]]  # Вложенные списки остаются неизменными

Альтернативные функции в Python

Python предлагает несколько функций для работы со случайностью, которые могут применяться в схожих сценариях.

random.sample(population, k) – возвращает новый список длиной k из уникальных элементов последовательности population. Предпочтительнее, когда требуется выбрать подмножество без повторений или когда исходная последовательность не должна изменяться.

import random
result = random.sample([1, 2, 3, 4, 5], 3)
print(result)
[5, 1, 3]

random.choices(population, weights=None, k=1) – возвращает список длиной k с возвращением элементов. Позволяет задавать веса для элементов. Используется, когда нужны повторяющиеся элементы или взвешенный случайный выбор.

import random
result = random.choices(['a', 'b', 'c'], k=4)
print(result)
['b', 'c', 'a', 'b']

numpy.random.shuffle() – аналог из библиотеки NumPy, работающий с массивами numpy. Обеспечивает более высокую производительность для больших числовых массивов и поддерживает многомерные массивы по указанной оси.

import numpy as np
arr = np.array([1, 2, 3, 4])
np.random.shuffle(arr)
print(arr)
[3 1 4 2]

sorted(iterable, key=lambda x: random.random()) – идиоматический способ создания перемешанной копии без изменения оригинала через сортировку по случайному ключу.

import random
original = [10, 20, 30, 40]
shuffled = sorted(original, key=lambda x: random.random())
print(shuffled)
[40, 10, 30, 20]

Аналоги в других языках программирования

JavaScript: метод array.sort() с функцией сравнения, возвращающей случайное значение.

let arr = [1, 2, 3, 4];
arr.sort(() => Math.random() - 0.5);
console.log(arr);
[3, 1, 4, 2]

Java: Collections.shuffle() из стандартной библиотеки.

import java.util.*;
List list = Arrays.asList(1, 2, 3, 4);
Collections.shuffle(list);
System.out.println(list);
[3, 1, 4, 2]

PHP: функция shuffle() работает аналогично, но переиндексирует массив.

$arr = [1, 2, 3, 4];
shuffle($arr);
print_r($arr);
Array ( [0] => 4 [1] => 1 [2] => 3 [3] => 2 )

C#: метод Random.Shuffle() для массивов и списков.

Random rng = new Random();
List list = new List {1, 2, 3, 4};
list = list.OrderBy(x => rng.Next()).ToList();
Console.WriteLine(string.Join(", ", list));
3, 1, 4, 2

Golang: в стандартной библиотеке отсутствует готовая функция, реализуется через интерфейс sort.Interface.

import (
    "math/rand"
    "time"
)
rand.Seed(time.Now().UnixNano())
arr := []int{1, 2, 3, 4}
rand.Shuffle(len(arr), func(i, j int) {
    arr[i], arr[j] = arr[j], arr[i]
})
fmt.Println(arr)
[4 2 1 3]

Kotlin: метод shuffle() для изменяемых коллекций.

val list = mutableListOf(1, 2, 3, 4)
list.shuffle()
println(list)
[3, 1, 4, 2]

Lua: отсутствует встроенная функция, требуется ручная реализация алгоритма Фишера-Йетса.

math.randomseed(os.time())
local t = {1, 2, 3, 4}
for i = #t, 2, -1 do
    local j = math.random(i)
    t[i], t[j] = t[j], t[i]
end
print(table.concat(t, ", "))
3, 1, 4, 2

SQL: порядок строк по умолчанию не гарантирован, для явного перемешивания используется ORDER BY RAND() в MySQL или ORDER BY random() в SQLite.

SELECT * FROM table_name ORDER BY RAND() LIMIT 5;

Типичные ошибки при использовании

Ошибка 1: Попытка перемешать неизменяемую последовательность

import random
tuple_data = (1, 2, 3, 4)
try:
    random.shuffle(tuple_data)
except TypeError as e:
    print(f"Ошибка: {e}")
Ошибка: 'tuple' object does not support item assignment

Ошибка 2: Непонимание того, что функция изменяет оригинальный список

import random
original = [1, 2, 3, 4]
shuffled = random.shuffle(original)
print("Оригинал:", original)
print("Результат функции:", shuffled)
Оригинал: [2, 4, 1, 3]
Результат функции: None

Ошибка 3: Использование строк вместо списка символов

import random
text = "abcd"
try:
    random.shuffle(text)
except TypeError as e:
    print(f"Ошибка: {e}")
Ошибка: 'str' object does not support item assignment

Ошибка 4: Передача неправильного типа в параметр random

import random
data = [1, 2, 3, 4]
try:
    random.shuffle(data, random=0.5)
except TypeError as e:
    print(f"Ошибка: {e}")
Ошибка: 'float' object is not callable

Изменения в последних версиях Python

В версии Python 3.11 были внесены изменения в реализацию алгоритма перемешивания. Теперь используется современная версия алгоритма Фишера-Йетса, которая обеспечивает более равномерное распределение.

В Python 3.9 появилась возможность использовать random.shuffle() с пользовательским генератором псевдослучайных чисел через параметр random, что повысило гибкость функции.

Начиная с Python 3.10, улучшена обработка ошибок для некорректных типов аргументов с более понятными сообщениями об ошибках.

Важное изменение в Python 3.11: для очень больших последовательностей (более 2^31 элементов) теперь корректно обрабатываются индексы за счет использования 64-битных целых чисел в реализации.

Расширенные примеры применения

Пример 1: Перемешивание колоды карт

Пример python
import random
suits = ['♠', '♥', '♦', '♣']
ranks = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']
deck = [rank + suit for suit in suits for rank in ranks]
random.shuffle(deck)
print("Первые 5 карт:", deck[:5])
Первые 5 карт: ['10♦', '4♠', 'J♣', '7♥', '2♠']

Пример 2: Создание тестовых данных с перемешанными метками

Пример python
import random
import numpy as np

X = np.array([[1, 2], [3, 4], [5, 6], [7, 8]])
y = [0, 1, 0, 1]
indices = list(range(len(X)))
random.shuffle(indices)
X_shuffled = X[indices]
y_shuffled = [y[i] for i in indices]
print("Перемешанные признаки:\n", X_shuffled)
print("Перемешанные метки:", y_shuffled)
Перемешанные признаки:
 [[5 6]
 [3 4]
 [7 8]
 [1 2]]
Перемешанные метки: [0, 1, 1, 0]

Пример 3: Параллельное перемешивание нескольких списков

Пример python
import random

names = ['Анна', 'Борис', 'Виктор', 'Дарья']
scores = [85, 92, 78, 95]

paired = list(zip(names, scores))
random.shuffle(paired)
names_shuffled, scores_shuffled = zip(*paired)

print("Имена:", names_shuffled)
print("Баллы:", scores_shuffled)
Имена: ('Борис', 'Дарья', 'Анна', 'Виктор')
Баллы: (92, 95, 85, 78)

Пример 4: Частичное перемешивание (алгоритм Саттоло)

Пример python
import random

def sattolo_shuffle(items):
    """Алгоритм Саттоло для создания случайного цикла"""
    i = len(items)
    while i > 1:
        i = i - 1
        j = random.randrange(i)
        items[i], items[j] = items[j], items[i]
    return items

numbers = [1, 2, 3, 4, 5]
print("Результат Саттоло:", sattolo_shuffle(numbers.copy()))
Результат Саттоло: [3, 5, 1, 4, 2]

Пример 5: Воспроизводимое перемешивание с фиксированным seed

Пример python
import random

def reproducible_shuffle(data, seed=42):
    random.seed(seed)
    random.shuffle(data)
    return data

list1 = [1, 2, 3, 4, 5]
list2 = [1, 2, 3, 4, 5]

print("Первый запуск:", reproducible_shuffle(list1, 42))
print("Второй запуск:", reproducible_shuffle(list2, 42))
Первый запуск: [2, 5, 1, 3, 4]
Второй запуск: [2, 5, 1, 3, 4]

Пример 6: Взвешенное перемешивание через кастомную random-функцию

Пример python
import random
import bisect

def weighted_shuffle(items, weights):
    """Перемешивание с учётом весов элементов"""
    cumulative_weights = []
    total = 0
    for w in weights:
        total += w
        cumulative_weights.append(total)
    
    def weighted_random():
        return bisect.bisect_left(cumulative_weights, random.random() * total)
    
    return sorted(items, key=lambda x: weighted_random())

colors = ['красный', 'зеленый', 'синий']
weights = [0.7, 0.2, 0.1]
print("Взвешенное перемешивание:", weighted_shuffle(colors, weights))
Взвешенное перемешивание: ['красный', 'зеленый', 'синий']

питон random.shuffle function comments

En
Random.shuffle Shuffle the sequence in place