Scritto da Reinder de Vries, il 12 luglio 2020 in Sviluppo App, Swift

FlatMap e CompactMap Spiegato in Swift

Swift ha un sacco di funzioni che sono utili per trasformare le collezioni e le sequenze. In questo tutorial, discuteremo map(_:), flatMap(_:)e compactMap(_:).

Ecco su cosa ci concentreremo:

  1. Come map(_:) trasforma una raccolta o una sequenza applicando una chiusura ad essa
  2. Come flatMap(_:) può appiattire un array di input, dopo aver chiamato map(_:)
  3. Come compactMap(_:) rimuove nil dall’array di input

In un precedente tutorial, abbiamo discusso come è possibile utilizzare filter(_:) e reduce(_:). Queste funzioni di ordine superiore sono super utili per trasformare le collezioni, in modo conciso e perspicace.

Pronto? Andiamo.

  1. Utilizzo della funzione Map in Swift
  2. Utilizzo della funzione FlatMap
  3. Utilizzo della funzione CompactMap
  4. Perché usare FlatMap e CompactMap?
  5. Ulteriori letture

Non hai ancora familiarità con le chiusure o le funzioni di ordine superiore? Assicurati di leggere su quelli prima:

  • La guida definitiva alle chiusure in Swift
  • Mappa, riduci e filtra in Swift

Utilizzando la funzione Mappa in Swift

Come aggiornamento rapido sulle funzioni di ordine superiore in Swift, il nostro punto di partenza è la funzione map(_:). Questa funzione applica una trasformazione a ciascuno degli elementi in una sequenza, come un array o un dizionario.

Ecco un esempio:

lasciate numbers =
lasciate result = numbers.mappa({ $0 * $0 })
stampa (risultato)
Nascondi avvisi

Scomponiamolo:

Innanzitutto, stiamo creando un array numbers con alcuni valori interi. Quindi, la funzione map(_:) viene chiamata su numberse il suo risultato viene assegnato a result.

La funzione map(_:) ha un parametro, una chiusura, che restituisce il risultato di . corrisponde al primo parametro della chiusura, ovvero il numero da numbers che viene trasformato.

Stiamo calcolando il quadrato di ogni numero in numbers. In sostanza, l’operazione viene chiamata su ogni numero in numberse l’array risultante viene assegnato a result. Stai trasformando – o” mappando ” – un array in un altro.

Trasformare un array con map(_:) è simile all’utilizzo di un ciclo for, ma molto più conciso. Così:

let numbers = var result = ()for number in numbers { result += }print(result)

Ecco un altro modo di guardarlo. Con map(_:), l’array di numeri di input viene trasformato in un altro array di numeri. Così:

2 => 2 * 2 => 43 => 3 * 3 => 94 => 4 * 4 => 165 => 5 * 5 => 25

Funzioni come map(_:) sono chiamate funzioni di ordine superiore, perché prendono una funzione come input rispetto ai valori ordinari. Funzioni di ordine superiore possono anche funzioni di output, che è utile per un paradigma di programmazione chiamato programmazione funzionale.

Tecnicamente, è possibile chiamare funzioni di ordine superiore come map(_:) su qualsiasi sequenza. Ciò include raccolte come array, dizionari e set, intervalli come 1...100 e i cosiddetti iteratori. Tutto ciò che sembra una “lista” di valori, fondamentalmente.

Discuteremo perché le funzioni di ordine superiore sono utili alla fine di questo tutorial. Passiamo prima a conoscere flatMap(_:)e compactMap(_:).

Vieni assunto come sviluppatore iOS

Impara a creare app iOS 14 con Swift 5

Iscriviti al mio corso di sviluppo iOS e scopri come iniziare la tua carriera come sviluppatore iOS professionista.

Utilizzando la funzione FlatMap

La funzione flatMap(_:) è simile a map(_:) tranne che “appiattisce” l’array risultante. Ecco un esempio:

lasciate numbers=,,]
lasciate result = numbers.flatMap ({0 0 })
stampa (risultato)
Nascondi avvisi

Il codice precedente inizia con una matrice nidificata di numeri interi. L’array numbers è costituito da un array di 3 array, ognuno dei quali contiene 3 numeri.

La chiusura { } restituisce semplicemente il primo argomento della chiusura, ovvero i singoli array nidificati. Nessuna trasformazione o operazione sta accadendo. Quando si chiama flatMap(_:) sull’array numbers, invece di map(_:), si finisce con una matrice appiattita di singoli numeri. A differenza dell’array di input numbers, l’array di risultati non contiene array nidificati!

Diamo un’occhiata ad un altro esempio. Immagina di lavorare con 4 gruppi di giraffe e di creare un singolo gruppo di giraffe più alte di una certa altezza. Ecco come si fa:

lasciate giraffe=,,]
lasciate più alto = giraffe.Mappa piatta ({0 0.filtro({ $0 > 10 }) })
stampa (più alto)
Nascondi avvisi

Vedi come giraffes contiene un array di array? Nel codice precedente, la funzione filter(_:) viene chiamata su ogni array nidificato all’interno di giraffes. Vogliamo solo numeri interi (giraffe!) che sono maggiori di 10. Gli array risultanti vengono appiattiti in un array “piatto” e assegnati a tallest.

Considera cosa succederebbe se avessimo usato map(_:) invece di flatMap(_:). L’array risultante non sarebbe appiattito. Invece, sarebbe questo:

, , ]

È importante notare che la funzione flatMap(_:) chiama prima map(_:) sugli elementi dell’array e quindi la appiattisce. Ecco perché qualcosa come il seguente non funziona:

let numbers = , , ]let result = numbers.flatMap({  * 2 })

Nel codice precedente, si riferisce agli array all’interno dei numeri. Moltiplicare un array per due è impossibile, ecco perché questo codice non funziona.

È intelligente pensare al flatmapping come a vedere un array in una dimensione in meno. Si inizia con un array bidimensionale e si finisce con un array unidimensionale dopo flatMap(_:).

Che ne dici di usare flatMap(_:) con gli optionals? Vediamo la prossima volta.

Il nome “mappa compatta” si basa sull’idea che la rimozione di nil elementi da un array rende l’array più compatto. Allo stesso modo, il nome “mappa piatta” deriva dall’appiattimento dell’array. E “mapping” è un concetto della matematica, in cui si associano i valori in un set con un altro set.

Utilizzando la funzione CompactMap

La funzione compactMap(_:) rimuove i valori nil dall’array di input. È super utile quando si lavora con gli optionals.

Prima di Swift 4.1, la funzione flatMap(_:) (sopra) potrebbe anche essere utilizzata per filtrare i valori nil dagli array appiattiti. Da Swift 4.1+, ora usi l’esplicito compactMap(_:) per questo scopo.

Ecco un esempio:

lasciate numbers =
lasciate result = numbers.compactMap ({Int (0 0) })
stampa (risultato)
Nascondi avvisi

Vedi cosa succede? La parte più importante del codice è Int(). Questo richiede una singola stringa da numbers con e tenta di convertire in un numero intero, con l’inizializzatore Int().

Questo inizializzatore Int() è fallibile: può restituire nil – un optional – quindi il suo tipo di ritorno è Int?. Di conseguenza, il tipo restituito della trasformazione di mappatura è

La funzione compactMap(_:) rimuove automaticamente gli elementi nil dall’array restituito, dopo aver chiamato map(_:) su di esso. Come tale, il suo tipo di ritorno non è facoltativo.

Nel codice precedente, il tipo di resultè . Se avresti usato map(_:), il tipo di ritorno sarebbe stato . E avresti avuto bisogno di un passo in più per scartare i valori dall’array, per lavorare con loro.

Perché usare FlatMap e CompactMap?

Prima di discutere i casi d’uso reali di flatmap e compactmap, facciamo un rapido riassunto di queste funzioni di ordine superiore e dei loro scopi.

  1. Il map(_:) funzione si applica una chiusura di una raccolta di input e restituisce la trasformata di raccolta
  2. Il flatMap(_:) funzione fa lo stesso, e anche appiattisce l’insieme risultante
  3. Il compactMap(_:) funzione esegue la stessa map(_:), e rimuove anche nil risultante dalla collezione

Lavorare con map(_:), flatMap(_:) e compactMap(_:) in astratto rende a volte difficile immaginare il loro utilizzo pratico dei casi. Discutiamo perché vorresti usarli.

Usare funzioni come map(_:) per applicare trasformazioni alle sequenze ha alcuni vantaggi:

  • È più conciso rispetto all’utilizzo di un ciclo for, perché non sono necessarie variabili temporanee e un blocco for in { } multilinea.
  • In genere è possibile scrivere una chiamata a map(_:) su una riga, che (di solito) rende il codice più leggibile.
  • Funzioni come map(_:) possono essere concatenate, in modo da poter applicare più trasformazioni a una sequenza una per una.

In generale, le funzioni di ordine superiore sono utili perché consentono di applicare una funzione a una sequenza di valori. Invece di codificare la trasformazione proceduralmente, puoi semplicemente applicare la funzione e ottenere un risultato.

Il caso d’uso più pratico per flatMap(_:) funziona con valori di input raggruppati o nidificati, ma il valore di output desiderato deve essere unidimensionale.

In un’app musicale, ad esempio, potresti avere 3 array: canzoni, artisti e playlist. Li si combinano in un array, chiamare flatMap(_:) su di esso, selezionare i brani, gli artisti e le playlist per i quali isFavorite è true e finire con un elenco piatto di elementi che sono stati preferiti.

Un caso d’uso pratico per compactMap(_:)sta lavorando con una trasformazione che può restituire nil. Ti risparmi alcuni passaggi banali lasciando che compactMap(_:) filtri immediatamente i valori nil. Un ulteriore vantaggio è il tipo di ritorno non opzionale compactMap(_:); la funzione filter(_:), in confronto, avrebbe restituito un valore opzionale se si è filtrato nil.

È possibile combinare flatMap(_:) e compactMap(_:), e anche filter(_:)o reduce(_:_:). Immagina di costruire un’app per i social media. Vuoi costruire una timeline di post per un utente. Si utilizzano 3 query per selezionare gli ID post per l’utente, ad esempio da post follower, pubblicità e argomenti di tendenza.

  • Puoi usare map(_:) per espandere questi ID in oggetti Post
  • Puoi usare flatMap(_:) per appiattire i 3 gruppi in un’unica raccolta
  • Puoi usare compactMap(_:) per scartare i post che non potevano essere espansi

Pulito!

Vieni assunto come sviluppatore iOS

Impara a creare app iOS 14 con Swift 5

Iscriviti al mio corso di sviluppo iOS e scopri come iniziare la tua carriera come sviluppatore iOS professionista.

Ulteriori letture

Vale la pena conoscere map(_:), flatMap(_:) e compactMap(_:), perché rendono il codice più conciso e leggibile. Puoi aggiungere una programmazione più funzionale al codice della tua app. Una volta che ti abitui a loro, non puoi credere di poter fare il tuo lavoro senza di loro.

In particolare le differenze tra map(_:), flatMap(_:) e compactMap(_:) vale la pena sottolineare. Il primo applica una trasformazione a una sequenza, il secondo appiattisce l’array risultante e il terzo rimuove i valori nil prima di restituire il risultato. Fantastico!

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.