トラック
/
jq
jq
/
演習
/
再帰関数
再帰関数

再帰関数

学習演習

はじめに

再帰

再帰関数とは、自分自身を呼び出す関数のことです。

_再帰関数_には、少なくとも1つの_基底ケース_と、少なくとも1つの_再帰ケース_が必要です。

基底ケースは、関数を再び呼び出さずに値を返します。 再帰ケースは、いずれ基底ケースに一致するように入力を変更しながら、関数を再び呼び出します。

次は、配列の要素を数える例です。

def count:
  if length == 0 then
    0                       # base case
  else
    1 + (.[1:] | count)     # recursive case
  end;

([] | count),           # => 0
([11, 22, 33] | count)  # => 3

_再帰関数_は、_基底ケース_を複数持つことも、_再帰ケース_を複数持つこともできます。 たとえば、フィボナッチ数列は、2つの_基底ケース_を持つ再帰的な数列です。

def fibonacci:
  if . == 0 then
    0
  elif . == 1 then
    1
  else
    (. - 1 | fibonacci) + (. - 2 | fibonacci)
  end;

10 | fibonacci          # => 55

ある値xが配列の中に何回現れるかを数える場合には、2つの_再帰ケース_があります。

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が内部でどう動いているか知っていますか? 一緒に確かめてみましょう。組み込みは使わず、再帰を使って自分で実装してみてください。」

1. 配列の数値を合計する関数を実装する

再帰の練習として、組み込みのaddフィルターを再実装してみましょう。 _基底ケース_は、空の配列の合計がゼロになることです。

組み込みのaddは使わず、再帰関数を使って自分で実装してください。

[5, 4, 6, 10] | array_add     # => 25

2. 配列を逆順にする

組み込みのreverseフィルターを再実装してみましょう。 _基底ケース_は、空の配列を逆順にすると空の配列になることです。

組み込みのreverseは使わず、再帰関数を使って自分で実装してください。

[5, 4, 6, 10] | array_reverse   # => [10, 6, 4, 5]

3. 配列をマップする

組み込みのmapフィルターを再実装してみましょう。 この関数はフィルターを仮引数として受け取り、入力の配列の各要素に対してそのフィルターを実行し、その結果を新しい配列として返します。 _基底ケース_は、空の配列をマップすると空の配列になることです。

組み込みのmapは使わず、再帰関数を使って自分で実装してください。

[5, 4, 6, 10] | array_map(. + 10)   # => [15, 14, 16, 20]
GitHubで編集する リンクは新しいウィンドウまたはタブで開きます
jq Exercism

再帰関数を始める準備はできましたか?

Exercismに登録すれば、12個のコンセプト75個の演習、そして本物の人間によるメンタリングとともに、jqを学んでマスターできます。すべて無料です。