Рекурсивні функції - це функції, які викликають самі себе.
Рекурсивна функція повинна мати щонайменше один базовий випадок і щонайменше один рекурсивний випадок.
Базовий випадок повертає значення, не викликаючи функцію знову. Рекурсивний випадок знову викликає функцію, змінюючи вхідні дані так, щоб рано чи пізно вони відповідали базовому випадку.
Ось приклад, який рахує елементи масиву.
def count:
if length == 0 then
0 # base case
else
1 + (.[1:] | count) # recursive case
end;
([] | count), # => 0
([11, 22, 33] | count) # => 3
Рекурсивна функція може мати багато базових випадків і/або багато рекурсивних випадків. Наприклад, послідовність Фібоначчі - це рекурсивна послідовність із двома базовими випадками.
def fibonacci:
if . == 0 then
0
elif . == 1 then
1
else
(. - 1 | fibonacci) + (. - 2 | fibonacci)
end;
10 | fibonacci # => 55
Підрахунок кількості входжень заданого значення x у масиві має два рекурсивні випадки.
def count_occurrences(x):
if length == 0 then
0
elif first == x then
1 + (.[1:] | count_occurrences(x))
else
(.[1:] | count_occurrences(x))
end;
[11, 22, 33, 22, 44] | count_occurrences(22) # => 2
На практиці перебирання масивів та інших перелічуваних структур даних найчастіше виконують за допомогою вбудованих функцій,
як-от map і reduce, або за допомогою потоків на кшталт [.[] | select(...)].
Під капотом деякі вбудовані функції реалізовано через рекурсію.
Ми щойно приєдналися до команди, яка підтримує конвеєр даних на основі jq.
Під час першого сеансу парного програмування наш новий колега зацікавився:
«Чи знаємо ми, як add, reverse і map працюють під капотом? Дослідімо і спробуймо реалізувати їх самостійно за допомогою рекурсії, без вбудованих фільтрів.»
Ми реалізуємо вбудований фільтр add заново, щоб попрактикуватися з рекурсією.
Базовий випадок такий: сума порожнього масиву дорівнює нулю.
Реалізуйте її самостійно за допомогою рекурсивної функції; не використовуйте вбудований add.
[5, 4, 6, 10] | array_add # => 25
Ми реалізуємо вбудований фільтр reverse заново.
Базовий випадок такий: якщо масив порожній, то й перевернутий масив порожній.
Реалізуйте його самостійно за допомогою рекурсивної функції; не використовуйте вбудований reverse.
[5, 4, 6, 10] | array_reverse # => [10, 6, 4, 5]
Ми реалізуємо вбудований фільтр map заново.
Функція приймає фільтр як параметр, запускає його для кожного елемента вхідного масиву та повертає вихідні дані в новому масиві.
Базовий випадок такий: порожній масив перетворюється на порожній масив.
Реалізуйте її самостійно за допомогою рекурсивної функції; не використовуйте вбудований map.
[5, 4, 6, 10] | array_map(. + 10) # => [15, 14, 16, 20]
Зареєструйтеся на Exercism, щоб вивчати й опановувати jq, а також 12 концепцій75 вправ та справжнє наставництво від людей, і все це безкоштовно.