Re

Reduce in jq

2 esercizi

Informazioni su Reduce

Supponiamo di voler sommare un array di numeri. Ci sono molti modi per raggiungere questo obiettivo.

  • In molti linguaggi, questo problema si esprime con un ciclo e una variabile accumulatore.

  • Questo problema può essere scritto come una funzione ricorsiva. In pseudocodice, potremmo avere questo.

    function Add(X, Sum=0):
      if X is empty then
        return Sum
      else
        return Add(rest(X), Sum + first(X))
      end
    end
    

    Questo metodo di suddividere il problema in parti più piccole si può descrivere anche come «ridurre verso il caso base».

Reduce è un modo per combinare tutti gli elementi di una struttura dati in un unico valore. Il processo itera sulla struttura dati, applicando una funzione a ogni elemento per aggiornare il risultato accumulato.

In jq, questo processo è implementato nel filtro reduce. In altri linguaggi potrebbe chiamarsi «fold», «fold-left», «inject» o «aggregate».

L'espressione reduce di jq si presenta così.

reduce STREAM_EXPRESSION as $var (INITIAL_VALUE; UPDATE_EXPRESSION)
  • STREAM_EXPRESSION è uno stream di elementi, ognuno memorizzato a turno nella variabile $var.
  • INITIAL_VALUE è il valore iniziale del risultato accumulato (noto come «accumulatore»).
  • L'espressione UPDATE_EXPRESSION combina («fold») il valore corrente ($var) nell'accumulatore.
    • Nel contesto di questa espressione, . è il valore dell'accumulatore.
    • L'output dell'espressione viene memorizzato nell'accumulatore per essere usato nell'iterazione successiva.
    • Dopo l'ultima iterazione, il risultato accumulato è l'output di reduce.

Vediamo un esempio: sommare i numeri di un array. Il filtro add fa esattamente questo, ma vedremo come implementarlo.

Se usiamo [10, 20, 30, 40] come input e prendiamo zero come stato iniziale, ogni passo si presenta così.

# stato elemento riduttore risultato
1 0 10 0 + 10 10
2 10 20 10 + 20 30
3 30 30 30 + 30 60
4 60 40 60 + 40 100

Nella sintassi di jq, il codice è questo.

0 + 10 | . + 20 | . + 30 | . + 40

Possiamo esprimerlo con il filtro reduce.

[10, 20, 30, 40] | reduce .[] as $n (0; . + $n)     # => 100
Note

La funzione incorporata add in realtà è implementata con reduce, ma usa «null» come stato iniziale (a null si può aggiungere qualsiasi tipo di dato).

def add: reduce .[] as $x (null; . + $x);

Alcune cose da tenere a mente

  • Nell'espressione di riduzione, . è l'accumulatore. Se l'input è un oggetto a cui devi fare riferimento all'interno della funzione di riduzione, devi memorizzarlo in una variabile.

    {"apple": 10, "banana": 16, "carrot": 4}
    | . as $obj
    | reduce (keys | .[]) as $key (0; . + $obj[$key])     # => 30
    
  • L'accumulatore può essere di qualsiasi tipo di dato. Per esempio potresti voler invertire un array.

    ["A", "B", "C", "D"]
    | reduce .[] as $elem ([]; [$elem] + .)       # => ["D", "C", "B", "A"]
    
Modifica tramite GitHub Il collegamento si apre in una nuova finestra o scheda

Impara Reduce

La pratica è bloccata

Sblocca 3 altri esercizi per esercitarti su Reduce