Найти в Дзене
Жонглер данными

Перебор значений без циклов

Мы продолжаем цикл лекций про numpy-программирование: первая статья, вторая и третья. Сегодня мы попробуем сгенерировать все варианты из двух списков. Конечно же есть удобная библиотека itertools, которая позволит получить нужный результат, но наша задача - написать алгоритм в новом стиле матричного программирования.

Стало уже доброй традицией формулировать задачу на конкретном примере. Не будем нарушать традиций. Пусть у нас будет два вектора по 5 элементов каждый: [1, 2, 3, 4, 5], [ 6, 7, 8, 9, 10], а результат должен выглядеть так:

Результирующая матрица
Результирующая матрица

Получить результат в классическом стиле очень даже просто:

Алгоритм в классическом варианте
Алгоритм в классическом варианте

Здесь использован list comprehension, что является запрещенным приемом, особенно, если в один цикл вложен другой. Приглядитесь внимательно к результирующей матрице: каждый элемент образован соединением повторением значений первого вектора и чуть другим повторением значений второго. А в библиотеке numpy есть нужные нам функции: repeat и tile. Объединить повторения можно функцией stack. Оформим все это в виде функции:

Функция перебора всех значений
Функция перебора всех значений

Начнем с функции repeat, как понятно из названия, она повторяет определенный массив, опеределенное количество раз, посмотрим как она это делает:

Результат выполнения функции repeat
Результат выполнения функции repeat

Теперь посмотрим как это делает функция tile:

Результат выполнения функции tile
Результат выполнения функции tile

Теперь все это надо соединить наподобие функции zip, то есть первый элемент первого вектора с первым элементом второго вектора. Именно это и делает функция stack с параметром axis=1.

Если мы подадим наши исходные вектора в текущую функцию, то получим результат аналогичный ожидаемому.

В качестве домашнего задания, подумайте: можно ли как-то переделать функцию для векторов разных размеров, например, 4 и 5.