Tegyük fel, hogy egy számtömb összegét szeretnénk kiszámítani. Ezt a célt többféleképpen is el lehet érni.
Sok nyelvben ezt a problémát egy ciklussal és egy akkumulátorváltozóval fejezik ki.
Ez a probléma rekurzív függvényként is megírható. Pszeudokódban valahogy így nézhet ki.
function Add(X, Sum=0):
if X is empty then
return Sum
else
return Add(rest(X), Sum + first(X))
end
end
Ez a módszer, amellyel a problémát kisebb darabokra bontjuk, úgy is leírható, mint „redukálás az alapeset felé”.
A reduce arra szolgál, hogy egy adatszerkezet összes elemét egyetlen értékké alakítsa. A folyamat végigiterál az adatszerkezeten, és minden elemre alkalmaz egy függvényt, hogy frissítse az akkumulált eredményt.
A jq-ban ezt a folyamatot a reduce szűrő valósítja meg.
Más nyelvekben ezt „fold”, „fold-left”, „inject” vagy „aggregate” néven ismerhetik.
A jq reduce kifejezés így néz ki.
reduce STREAM_EXPRESSION as $var (INITIAL_VALUE; UPDATE_EXPRESSION)
STREAM_EXPRESSION egy stream, amelynek elemei sorra a $var változóba kerülnek.
.[] szűrőt: $myArray | .[].INITIAL_VALUE az akkumulált eredmény kezdőértéke (ezt nevezik „akkumulátornak”).UPDATE_EXPRESSION összekombinálja („belehajtja”) az aktuális értéket ($var) az akkumulátorba.
. az akkumulátor értéke.reduce kimenete.Nézzünk egy példát: adjuk össze egy tömb elemeit.
Az add szűrő pontosan ezt teszi, de most megnézzük, hogyan lehet megvalósítani.
Ha a [10, 20, 30, 40] tömböt adjuk meg bemenetként, és nullát veszünk kezdeti állapotnak, akkor az egyes lépések így néznek ki.
| # | állapot | elem | redukáló | eredmény |
|---|---|---|---|---|
| 1 | 0 | 10 | 0 + 10 | 10 |
| 2 | 10 | 20 | 10 + 20 | 30 |
| 3 | 30 | 30 | 30 + 30 | 60 |
| 4 | 60 | 40 | 60 + 40 | 100 |
A jq szintaxisban ez a kód így néz ki:
0 + 10 | . + 20 | . + 30 | . + 40
Ezt kifejezhetjük a reduce szűrővel.
[10, 20, 30, 40] | reduce .[] as $n (0; . + $n) # => 100
A beépített add valójában a reduce szűrővel van megvalósítva, de a „null” értéket használja kezdeti állapotként (a nullhoz bármilyen adattípus hozzáadható).
def add: reduce .[] as $x (null; . + $x);
A redukáló kifejezésben a . az akkumulátor.
Ha a bemenet egy olyan objektum, amelyre a redukáló függvényben hivatkoznod kell, el kell tárolnod egy változóban.
{"apple": 10, "banana": 16, "carrot": 4}
| . as $obj
| reduce (keys | .[]) as $key (0; . + $obj[$key]) # => 30
Az akkumulátor bármilyen adattípusú lehet. Például előfordulhat, hogy meg akarsz fordítani egy tömböt.
["A", "B", "C", "D"]
| reduce .[] as $elem ([]; [$elem] + .) # => ["D", "C", "B", "A"]