Tegyük fel, hogy össze szeretnénk adni egy számtömböt. Ezt a célt többféleképpen is elérhetjük.
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 problémafelosztási módszer úgy is leírható, mint „redukálás az alapeset felé”.
A Reduce olyan módszer, amellyel egy adatszerkezet összes elemét egyetlen értékké lehet összevonni. A folyamat végigiterál az adatszerkezeten, minden elemre alkalmazva egy függvényt, hogy frissítse a felhalmozott eredményt.
A jq-ban ezt a folyamatot a reduce szűrő valósítja meg.
Más nyelvekben lehet, hogy „fold”, „fold-left”, „inject” vagy „aggregate” a neve.
A jq reduce kifejezése így néz ki.
reduce STREAM_EXPRESSION as $var (INITIAL_VALUE; UPDATE_EXPRESSION)
STREAM_EXPRESSION elemek egy stream-je, amelyek sorra a $var változóba kerülnek.
.[] használd: $myArray | .[].INITIAL_VALUE a felhalmozott eredmény kezdőértéke (ezt nevezik „akkumulátornak”).UPDATE_EXPRESSION összevonja („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 számait.
Az add szűrő pontosan ezt csinálja, de lássuk, hogyan lehet megvalósítani.
Ha a [10, 20, 30, 40] a bemenet, és a kezdőállapot nulla, 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 |
jq-szintaxisban ez így néz ki.
0 + 10 | . + 20 | . + 30 | . + 40
Ezt a reduce szűrővel fejezhetjük ki.
[10, 20, 30, 40] | reduce .[] as $n (0; . + $n) # => 100
Az add beépített valójában a reduce-dzsal van megvalósítva, de „null”-t használ kezdőállapotként (bármilyen adattípus hozzáadható a nullhoz).
def add: reduce .[] as $x (null; . + $x);
A redukáló kifejezésben a . az akkumulátor.
Ha a bemenet egy olyan objektum, amire a redukáló függvényen belül hivatkozni szeretnél, 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 meg szeretnél fordítani egy tömböt.
["A", "B", "C", "D"]
| reduce .[] as $elem ([]; [$elem] + .) # => ["D", "C", "B", "A"]
Tanár vagy. Az év végén minden tanulódhoz kiszámoltál egy numerikus osztályzatot. Most át kell alakítanod ezeket betűjegyekké, és meg kell számolnod, hány tanuló érte el az egyes betűjegyeket.
A letter_grade függvény bemenetként egy numerikus osztályzatot kap, és kiadja a hozzá tartozó betűt.
Ezeket a tartományokat használd:
| Betű | Osztályzat |
|---|---|
| A | 90% - 100% |
| B | 80% - 89% |
| C | 70% - 79% |
| D | 60% - 69% |
| F | 0% - 59% |
Példa:
75 | letter_grade # => "C"
A count_letter_grades függvény egy olyan objektumot kap, amely a tanulók nevét az osztályzataikhoz rendeli.
A kimenet egy olyan objektum lesz, amely minden betűjegyhez a hozzá tartozó tanulók számát rendeli.
Példa:
{"Joe": 78, "Jane": 93, "Richard": 72} | count_letter_grades
# => {"A": 1, "B": 0, "C": 2, "D": 0, "F": 0}
Ezt többféleképpen is meg lehet oldani.
Gyakorlásként használd a reduce szűrőt.
Iratkozz fel az Exercism-re, hogy megtanuld és elsajátítsd a(z) jq nyelvet 12 fogalom75 feladat segítségével, valódi emberi mentorálással, mindez ingyen.