Comprehension и генераторы

Компактный способ создать массив по правилу — array comprehension, знакомый по Python, но с нюансами.

Comprehension — выражение, которое строит массив, применяя формулу к каждому значению из диапазона или коллекции.

Базовый синтаксис

Comprehension записывается в квадратных скобках: «выражение for переменная in коллекция».

squares = [x^2 for x in 1:5]
println(squares)

Вывод:

[1, 4, 9, 16, 25]

Это короче и часто быстрее, чем заводить пустой массив и наполнять его в цикле через push!.

С условием-фильтром

Можно добавить if, чтобы оставить только подходящие элементы:

evens = [x for x in 1:10 if x % 2 == 0]
println(evens)

Вывод:

[2, 4, 6, 8, 10]

Вложенные comprehension

Два цикла подряд создают многомерный результат — это удобно для матриц:

table = [i * j for i in 1:3, j in 1:3]
println(table)

Вывод:

[1 2 3; 2 4 6; 3 6 9]

Здесь получилась матрица 3×3 — таблица умножения. Запятая между двумя for создаёт именно матрицу, а не плоский вектор.

Генераторы: ленивая версия

Если убрать квадратные скобки и оставить круглые (или передать выражение прямо в функцию), comprehension становится генератором — он не создаёт массив, а выдаёт значения по одному. Это экономит память, когда нужно лишь просуммировать или найти максимум:

total = sum(x^2 for x in 1:1000)
println(total)

Вывод:

333833500

Здесь миллион квадратов не материализуется в массив — sum получает их по одному.

Как работает под капотом

Comprehension в Julia — это синтаксический сахар над циклом, но с важным преимуществом: компилятор часто может заранее определить тип элементов и сразу выделить массив нужного типа и размера. Поэтому результат comprehension обычно имеет конкретный тип вроде Vector{Int64}, а не Vector{Any}, что важно для скорости. Генератор же не выделяет память под результат вовсе — значения вычисляются лениво в момент потребления.

Частые ошибки

Распространённая путаница — разница между [... for i in A, j in B] (создаёт матрицу) и [... for i in A for j in B] (создаёт плоский вектор из вложенных циклов). Запятая даёт декартово произведение в виде матрицы, два отдельных for — «выпрямленный» вектор. Выбирайте форму осознанно.

Итоги

  • Comprehension компактно строит массив: [x^2 for x in 1:5].
  • Фильтр добавляется через if: [x for x in 1:10 if x % 2 == 0].
  • Запятая между for создаёт матрицу; два for — плоский вектор.
  • Генератор (без квадратных скобок) ленив и экономит память.
Проверьте себя
1. Что вернёт [x^2 for x in 1:4]?
A[1, 2, 3, 4]
B[1, 4, 9, 16]
C[2, 4, 6, 8]
DОшибку
2. В чём преимущество генератора (sum(x for x in 1:1000)) перед comprehension в квадратных скобках?
AОн быстрее печатает
BОн не создаёт промежуточный массив, экономя память
CОн округляет результат
DНикакой разницы нет