# Flat/FlatMap do Javascript na Prática

Aprendendo a utilizar as novas operações de Array do Javascript

# **A proposta**

Foram confirmadas recentemente as novas propostas de funcionalidades que chegaram no [estágio 4](https://tc39.github.io/process-document/) do [ECMAScript](https://pt.wikipedia.org/wiki/ECMAScript), significando que estarão na proxima especificação oficial e terão sua implementação na linguagem!!

Dentre elas temos dois novos bebês ❤ chamados `Array.prototype.flat()` e o `Array.prototype.flatMap()`, baseados na [proposta do Michael Ficarra, Brian Terlson, Mathias Bynens](https://github.com/tc39/proposal-flatMap). Mas qual a importancia deles e como podemos utiliza-los?

O ***flatMap****(Muitas vezes chamado de concatMap ou &gt;&gt;= em outras linguagens)* é um pattern comum que vem da programação funcional de linguagens como *Scala* ou *Haskell.* Esta operação de *array* pode nos ajudar solucionar problemas em que temos de iterar por exemplo, arrays com itens complexos. Você pode já ter ouvido falar de [implementações similares de Flatmap por exemplo no RxJS para lidar com Observables](https://www.learnrxjs.io/operators/transformation/mergemap.html).

Mas diferente de outras linguagens, que utilizam o ***flatMap*** como uma operação para manipular ***objetos, strings***, tendo usos até mesmo como meio de lidar com valores ***opcionais*** e ***monadas.*** A sua implementação no Javascript se limita a **apenas operações de *arrays.***

Estamos familiares com funções como o \*\*\*[map\*\*\*, ***filter*** e ***reduce***](http://equinocios.com/swift/2017/03/13/Introducao-e-casos-de-uso-Map-Filter-e-Reduce/) que são responsáveis por transformar os elementos do arrays em novos valores a partir de uma função.

```plaintext
.map// [2, 3, 4]filter// [1 , 3]reduce// 6
```

Similarmente, o ***flatMap*** recebe uma função como argumento e funde os conceitos de ***flat*** com o já conhecido ***map****.*

Mas o que é o flat?

# **Array.prototype.flat()**

O `Array.prototype.flat()`, também conhecido como *flatten*, tem o intuito de deixar nosso array plano recursivamente em uma profundidade especificada como argumento, ou seja, é uma operação que concatena os elementos de um *array.*

Por padrão a função de *flat* planifica em um nível(`.flat(1)`) como no exemplo:

```plaintext
.flat// [ 1, 2, 3, 4].flat// [ 1, 2, 3, 4, [5, 6]]
```

Passando o número 2 como argumento a função fica plana em 2 níveis.

```plaintext
.flat// [ 1, 2, 3, 4, 5, 6 ]
```

# **Alguns usos praticos do Flat**

**Concatenando arrays**

Supondo dois arrays contendo alguns números que devem ser concatenados em apenas um array.

```plaintext
constconst
```

Uma forma de fazer isso seria mutar algum destes arrays e utilizar a operação ***push*** para inserir os valores do outro array dentro do outro.

```plaintext
.push// [1, 2, 3, 4, 5, 6]
```

Outro método comum caso eu queria criar um novo array seria utilizar o [*spread*](https://medium.com/magnetis-backstage/p%C3%ADlulas-de-javascript-operador-spread-e-par%C3%A2metro-rest-afd1f0266036) dos arrays dentro de um novo array concatenando seus elementos.

```plaintext
const// [1, 2, 3, 4, 5, 6]
```

A operação de ***flat*** nos introduz uma maneira interessante sem a necessidade de *spreads* para concatenar o elementos deste array.

```plaintext
flat
```

**Condicionalmente inserindo valores em um array.**

Supondo que caso uma condição seja verdadeira, devo inserir um valor dentro de um array.

Uma forma mais sucinta seria ao invés de um “if”, considerar essa condicional na propria criação array, colocando um ternário no proprio array. Caso a condição é verdadeira, insere o valor ‘a’, caso contrário insere *null*.

```plaintext
constconst?:// ['b', null]
```

Em condições positivas teremos o elemento esperado ‘a’, mas caso contrário teremos um array sujo com valores *“null”* e para isso seria necessário de alguma forma filtrar esses valores.

```plaintext
filter// ['b']
```

Com o *flat* podemos fazer de forma simples a inserção de valores caso a condição é verdadeira com uma condicional (`cond **?** ['a'] **:** []`). Pois já que o proprio flat concatena arrays, a concatenação de um array vazio caso uma condição falsa não geraria a insersão de valores desnecessários.

```plaintext
constconst?:.flat// ['b']
```

**Criando uma copia de um array**

Quando queremos criar uma copia de um *arr* mudando sua referencia.

```plaintext
constconstflat// [1,2,3,[4]]// [3,2,3,[4]]
```

Note que isso vai apenas retornar uma “*shallow copy*”. Ou seja, objetos dentro do array não serão clonados.

# **Array.prototype.flatMap()**

O ***flatMap*** é basicamente um ***map*** com ***flat***. Como assim?

Com o ***map***, cada elemento do array é iterado e apartir de uma função`f`retorna um novo array com cada um desses valores transformados. A função `f`que recebe um elemento *input* e torna um elemento *output*.

Com o ***flatMap***, cada elemento é iterado e apartir de uma função `f` retorna um array de valores. A função `f`que recebe um elemento *input* e e cada elemento pode ser transformado em nenhum ou mais elementos de *output*.

![https://miro.medium.com/max/60/1*aVV-YQA8RRx0R6ZV32MGEA.jpeg?q=20](https://miro.medium.com/max/60/1*aVV-YQA8RRx0R6ZV32MGEA.jpeg?q=20 align="left")

![https://miro.medium.com/max/2560/1*aVV-YQA8RRx0R6ZV32MGEA.jpeg](https://miro.medium.com/max/2560/1*aVV-YQA8RRx0R6ZV32MGEA.jpeg align="left")

Relação entre Map(One to one) e FlatMap(One to many)

Ambos ***flatMap*** e ***map*** recebem uma função `f` como argumento que gera um novo array de retorno com base nos items do array de origem.

Sequencialmente o ***flatMap*** seria similar a aplicação de uma função dentro de um ***map*** seguido de uma operação de ***flat*** planificando o *Array*.

```plaintext
map//[[1, 100], [2, 200], [3, 300]].flat() // [1, 100, 2, 200, 3, 300]flatMap// [1, 100, 2, 200, 3, 300]
```

Similarmente, usando o ***flatMap*** com uma função identidade(`x => x`), em que inutilizamos o seu ***map***, temos exatamente o que seria apenas um ***flat***.As seguintes operações são equivalentes:

```plaintext
flatMapmapflatflat
```

# **Alguns usos praticos do FlatMap**

**Filtrar e transformar arraysExemplo 1**

Podemos utilizar a operação de flapMap() como meio de filtrar elementos em arrays e transforma-los.

Supondo uma array de numeros de 1 a 10.

```plaintext
const
```

Queremos transformar este array em apenas numeros **antecessores** de **numeros primos**. Supondo que eu tenho uma função *isPrime* que me retorna verdadeiro ou falso caso o numéro é um primo. Podemos primeiramente utilizar a função *filter* para filtrar os valores em apenas primos\*.\*

```plaintext
filterisPrime// [2, 3, 5, 7]
```

Porém para listar os antecessores do array teriamos de **novamente** iterar pelos itens para retornar um novo array com cada valor subtraido por 1.

```plaintext
filterisPrimemap// [1, 2, 4, 6]
```

Com o ***flatMap*** podemos fazer ambas as operações em apenas uma iteração de array em que com uma operação ternária retornamos ou um array com o valor subtraido por 1 ou uma array vazio.

```plaintext
flatMapisPrime?:// [1, 2, 4, 6]
```

Sendo assim: é um ***map***, que iteraria os 10 elementos do *array* e geraria 10 *arrays*, seguido de um ***flat*** planificando em apenas um *array*:

```plaintext
map// [[],[1],[2],[],[4],[],[6]..]flat// [1, 2, 4, 6]
```

**Exemplo 2**

Tenho um array de ids de objetos e uma propriedade booleana indicando se este item deve ou não ser listado, se sim devo dar fetch nesta propriedade.

```plaintext
constidtoListidtoList
```

Sem o ***flatMap*** uma solução viavel seria utilizar o ***filter*** para filtrar caso a propriedade *toList* é verdadeira e em seguida seria necessário utilizar um ***map*** para efetivamente dar fetch nesses ids.

```plaintext
filtermap// [Promise]
```

Com apenas um flatMap podemos resolver este problema criando uma função em que caso o *toList* é verdadeiro ele retorna um array com o fetch do id, caso contrário retorna um array vazio que será concatenado.

```plaintext
Promise.allflatMap// [...]
```

**Exemplo 3**

Podemos usar para extrairmos apenas um tipo de dado de um objeto em tratativas. Por exemplo, em um array de objetos cuja tratativa de erros de um ***try / catch*** retorna apenas os valores dos resultados ou apenas os erros.

```plaintext
tryreturncatchreturn
```

***flatMap*** pode ser nosso aliado para podermos extrair apenas os erros ou apenas os valores especificos destes resultados por meio de uma operação ternária:

```plaintext
constflatMapconstflatMap
```

**Pegando elementos de um array de objetos com arrays aninhados.**

Supondo que tenho um array de objetos de cestas de frutas em que dentro do objetos listamos em “itens” as frutas dentro da cesta.

```plaintext
constiditensMaçaBananaiditensBananaAbacaxi
```

Se quero listar todas as frutas dentro de cestas no map seria necessário iterar pelo array e pegar a propriedade “itens” de cada objeto.

```plaintext
map// [Array(2), Array(2)]
```

Apenas com o map teriamos *arrays* de *arrays*.

```plaintext
flatMap// [“Maça”, “Banana”, “Banana”, “Abacaxi”]
```

Com o ***flatMap*** já temos a concatenação dos elementos do array e conseguimos obter todos os elementos listados dentro de objetos.

**Indexando em lista**

Supondo uma lista de compras, para listá-las entre vírgulas em um componente “GroceryList” podemos utilizar o ***flatMap.*** A função cujo metodo recebe pode ter um segundo argumento com o index do array assim como o ***map*** ou ***filter***. Por exemplo:

```plaintext
.map// ['0Foo', '1Bar']
```

Quando retornamos um array desta função, os seus elementos são concatenados e podemos adicionar elementos condicionais (como por exemplo, a vírgula após o primeiro elemento da lista).

```plaintext
classextendsrenderconstthisreturnflatMapfoodindexindexindexfoodfood
```

# **Suporte de Navegadores**

O ***flat*** e o ***flatMap*** já estão com suporte nos principais navegadores(*Chrome 69, Firefox 62, Opera 56, Safari 12, Android WebView 69*) e na versão *11.0.0* do *NodeJs ❤️🧡💛💚💙💜.*

É possivel tambem importar proposals pelo *Babel 7*. Pelo *FlatMap* já estar em *stage 4* é [preciso importar especificamente a funcionalidade.](https://babeljs.io/docs/en/v7-migration#remove-proposal-polyfills-in-babel-polyfill-https-githubcom-babel-babel-issues-8416)

# **Conclusão**

Cada vez mais vemos mudanças para agradar todas as formas / paradigmas do Javascript. Desde 2015 vemos a linguagem suportando outros estilos de orientação a objetos, e agora vemos a adição de elementos comuns de linguagens funcionais como ***FlatMap*** e quem sabe futuramente o [***Pipeline Operator***](https://github.com/tc39/proposal-pipeline-operator), [***Pattern Matching***](https://github.com/tc39/proposal-pattern-matching) e [***Partial Application***](https://github.com/tc39/proposal-partial-application) 🤞.

# **Espero que você tenha gostado do artigo ❤**

**Quem gostou bate palminha pra que o artigo alcançe outros amiguinhos.👏 👏 👏 👏 👏 👏 👏 👏 👏**
