Elisir - Enumerabili

Un enumerabile è un oggetto che può essere enumerato. "Enumerato" significa contare i membri di un set / collezione / categoria uno per uno (di solito in ordine, di solito per nome).

Elixir fornisce il concetto di enumerabili e il modulo Enum per lavorare con loro. Le funzioni nel modulo Enum sono limitate, come dice il nome, all'enumerazione dei valori nelle strutture dati. Esempio di una struttura dati enumerabile è una lista, tupla, mappa, ecc. Il modulo Enum ci fornisce poco più di 100 funzioni per gestire le enumerazioni. Discuteremo alcune importanti funzioni in questo capitolo.

Tutte queste funzioni prendono un enumerabile come primo elemento e una funzione come secondo e lavorano su di esse. Le funzioni sono descritte di seguito.

tutti?

Quando usiamo all? , l'intera raccolta deve essere valutata come true altrimenti verrà restituito false. Ad esempio, per verificare se tutti gli elementi nell'elenco sono numeri dispari, allora.

res = Enum.all?([1, 2, 3, 4], fn(s) -> rem(s,2) == 1 end) 
IO.puts(res)

Quando il programma di cui sopra viene eseguito, produce il seguente risultato:

false

Questo perché non tutti gli elementi di questo elenco sono dispari.

qualunque?

Come suggerisce il nome, questa funzione restituisce true se qualsiasi elemento della raccolta restituisce true. Ad esempio:

res = Enum.any?([1, 2, 3, 4], fn(s) -> rem(s,2) == 1 end)
IO.puts(res)

Quando il programma di cui sopra viene eseguito, produce il seguente risultato:

true

pezzo

Questa funzione divide la nostra collezione in piccoli pezzi della dimensione fornita come secondo argomento. Ad esempio:

res = Enum.chunk([1, 2, 3, 4, 5, 6], 2)
IO.puts(res)

Quando il programma di cui sopra viene eseguito, produce il seguente risultato:

[[1, 2], [3, 4], [5, 6]]

ogni

Potrebbe essere necessario iterare su una raccolta senza produrre un nuovo valore, in questo caso usiamo il each funzione -

Enum.each(["Hello", "Every", "one"], fn(s) -> IO.puts(s) end)

Quando il programma di cui sopra viene eseguito, produce il seguente risultato:

Hello
Every
one

carta geografica

Per applicare la nostra funzione a ogni articolo e produrre una nuova collezione utilizziamo la funzione mappa. È uno dei costrutti più utili nella programmazione funzionale poiché è abbastanza espressivo e breve. Consideriamo un esempio per capirlo. Raddoppieremo i valori memorizzati in un elenco e li memorizzeremo in un nuovo elencores -

res = Enum.map([2, 5, 3, 6], fn(a) -> a*2 end)
IO.puts(res)

Quando il programma di cui sopra viene eseguito, produce il seguente risultato:

[4, 10, 6, 12]

ridurre

Il reducela funzione ci aiuta a ridurre il nostro enumerabile a un singolo valore. Per fare questo, forniamo un accumulatore opzionale (5 in questo esempio) da passare alla nostra funzione; se non è previsto alcun accumulatore, viene utilizzato il primo valore -

res = Enum.reduce([1, 2, 3, 4], 5, fn(x, accum) -> x + accum end)
IO.puts(res)

Quando il programma di cui sopra viene eseguito, produce il seguente risultato:

15

L'accumulatore è il valore iniziale passato a fn. Dalla seconda chiamata in poi il valore restituito dalla chiamata precedente viene passato come accum. Possiamo anche usare ridurre senza l'accumulatore -

res = Enum.reduce([1, 2, 3, 4], fn(x, accum) -> x + accum end)
IO.puts(res)

Quando il programma di cui sopra viene eseguito, produce il seguente risultato:

10

uniq

La funzione uniq rimuove i duplicati dalla nostra raccolta e restituisce solo l'insieme di elementi nella raccolta. Ad esempio:

res = Enum.uniq([1, 2, 2, 3, 3, 3, 4, 4, 4, 4])
IO.puts(res)

Quando si esegue il programma sopra, produce il seguente risultato:

[1, 2, 3, 4]

Valutazione desiderosa

Tutte le funzioni nel modulo Enum sono entusiaste. Molte funzioni si aspettano un enumerabile e restituiscono un elenco. Ciò significa che quando si eseguono più operazioni con Enum, ciascuna operazione genererà un elenco intermedio fino a quando non si raggiunge il risultato. Consideriamo il seguente esempio per capire questo:

odd? = &(odd? = &(rem(&1, 2) != 0) 
res = 1..100_000 |> Enum.map(&(&1 * 3)) |> Enum.filter(odd?) |> Enum.sum 
IO.puts(res)

Quando il programma di cui sopra viene eseguito, produce il seguente risultato:

7500000000

L'esempio sopra ha una pipeline di operazioni. Iniziamo con un intervallo e poi moltiplichiamo ogni elemento nell'intervallo per 3. Questa prima operazione ora creerà e restituirà un elenco con 100_000 elementi. Quindi teniamo tutti gli elementi dispari dall'elenco, generando un nuovo elenco, ora con 50_000 elementi, e quindi sommiamo tutte le voci.

Il |> il simbolo utilizzato nello snippet sopra è il pipe operator: prende semplicemente l'output dall'espressione sul lato sinistro e lo passa come primo argomento alla chiamata di funzione sul lato destro. È simile a Unix | operatore. Il suo scopo è evidenziare il flusso di dati trasformato da una serie di funzioni.

Senza il pipe operatore, il codice sembra complicato -

Enum.sum(Enum.filter(Enum.map(1..100_000, &(&1 * 3)), odd?))

Abbiamo molte altre funzioni, tuttavia, solo alcune importanti sono state descritte qui.