Re

Reduce σε jq

2 ασκήσεις

Σχετικά με την έννοια Reduce

Ας υποθέσουμε ότι θέλουμε να αθροίσουμε έναν πίνακα αριθμών. Υπάρχουν πολλοί τρόποι για να πετύχουμε αυτόν τον σκοπό.

  • Σε πολλές γλώσσες, αυτό το πρόβλημα εκφράζεται ως βρόχος με μια μεταβλητή συσσωρευτή.

  • Αυτό το πρόβλημα μπορεί να γραφτεί ως αναδρομική συνάρτηση. Σε ψευδοκώδικα, θα μπορούσαμε να έχουμε κάτι τέτοιο.

    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.
  • Το 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
Note

Το ενσωματωμένο 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"]
    
Επεξεργασία μέσω GitHub Ο σύνδεσμος ανοίγει σε νέο παράθυρο ή καρτέλα

Μάθε την έννοια Reduce

Η εξάσκηση είναι κλειδωμένη

Ξεκλείδωσε 3 ακόμη ασκήσεις για να εξασκηθείς στην έννοια Reduce