Ας υποθέσουμε ότι θέλουμε να αθροίσουμε έναν πίνακα αριθμών. Υπάρχουν πολλοί τρόποι για να πετύχουμε αυτόν τον σκοπό.
Σε πολλές γλώσσες, αυτό το πρόβλημα εκφράζεται ως βρόχος με μια μεταβλητή συσσωρευτή.
Αυτό το πρόβλημα μπορεί να γραφτεί ως αναδρομική συνάρτηση. Σε ψευδοκώδικα, θα μπορούσαμε να έχουμε κάτι τέτοιο.
function Add(X, Sum=0):
if X is empty then
return Sum
else
return Add(rest(X), Sum + first(X))
end
end
Αυτή η μέθοδος διάσπασης του προβλήματος σε μικρότερα κομμάτια μπορεί επίσης να περιγραφεί ως "αναγωγή προς τη βασική περίπτωση".
Το Reduce είναι ένας τρόπος να συνδυάσεις όλα τα στοιχεία μιας δομής δεδομένων σε μία μόνο τιμή. Η διαδικασία διατρέχει τη δομή δεδομένων, εφαρμόζοντας μια συνάρτηση σε κάθε στοιχείο για να ενημερώσει το συσσωρευμένο αποτέλεσμα.
Στη jq, αυτή η διαδικασία υλοποιείται με το φίλτρο reduce.
Σε άλλες γλώσσες, μπορεί να ονομάζεται "fold", "fold-left", "inject" ή "aggregate".
Η έκφραση reduce της jq μοιάζει κάπως έτσι.
reduce STREAM_EXPRESSION as $var (INITIAL_VALUE; UPDATE_EXPRESSION)
STREAM_EXPRESSION είναι ένα stream από στοιχεία, καθένα από τα οποία αποθηκεύεται με τη σειρά στη μεταβλητή $var.
.[]: $myArray | .[].INITIAL_VALUE είναι η αρχική τιμή του συσσωρευμένου αποτελέσματος (γνωστή ως "συσσωρευτής").UPDATE_EXPRESSION συνδυάζει ("διπλώνει") την τρέχουσα τιμή ($var) μέσα στον συσσωρευτή.
. είναι η τιμή του συσσωρευτή.reduce.Ας δούμε ένα παράδειγμα: το άθροισμα των αριθμών ενός πίνακα.
Το φίλτρο add κάνει ακριβώς αυτό, αλλά θα δούμε πώς να το υλοποιήσουμε.
Αν χρησιμοποιήσουμε το [10, 20, 30, 40] ως είσοδο και πάρουμε το μηδέν ως αρχική κατάσταση, κάθε βήμα μοιάζει κάπως έτσι.
| # | κατάσταση | στοιχείο | αναγωγή | αποτέλεσμα |
|---|---|---|---|---|
| 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, αυτό μοιάζει με τον παρακάτω κώδικα.
0 + 10 | . + 20 | . + 30 | . + 40
Μπορούμε να το εκφράσουμε αυτό με το φίλτρο reduce.
[10, 20, 30, 40] | reduce .[] as $n (0; . + $n) # => 100
Το ενσωματωμένο add στην πραγματικότητα υλοποιείται με το reduce, αλλά χρησιμοποιεί το "null" ως αρχική κατάσταση (οποιοσδήποτε τύπος δεδομένων μπορεί να προστεθεί στο null).
def add: reduce .[] as $x (null; . + $x);
Στην έκφραση αναγωγής, το . είναι ο συσσωρευτής.
Αν η είσοδος είναι κάποιο αντικείμενο που χρειάζεται να αναφέρεις μέσα στη συνάρτηση αναγωγής, πρέπει να το αποθηκεύσεις σε μια μεταβλητή.
{"apple": 10, "banana": 16, "carrot": 4}
| . as $obj
| reduce (keys | .[]) as $key (0; . + $obj[$key]) # => 30
Ο συσσωρευτής μπορεί να είναι οποιουδήποτε τύπου δεδομένων. Για παράδειγμα, μπορεί να θέλεις να αντιστρέψεις έναν πίνακα.
["A", "B", "C", "D"]
| reduce .[] as $elem ([]; [$elem] + .) # => ["D", "C", "B", "A"]