Map x flatMap, entendendo a diferença na prática
Tags: javascript, programming, tutorial, braziliandevs
Published: 2023-01-05 11:50:47

Neste artigo veremos a diferença entre as funções `map()` e `flatMap()`, inclusive como implementar esta última para que possamos escrever um código mais elegante. Vamos ao problema.

```jsx
const notas = [
    {
        data: '2017-10-31',
        itens: [
            { conta: '2143', valor: 200 },
            { conta: '2111', valor: 500 }
        ]
    },
    {
        data: '2017-07-12',
        itens: [
            { conta: '2222', valor: 120 },
            { conta: '2143', valor: 280 }
        ]
    }, 
    {
        data: '2017-02-02',
        itens: [
            { conta: '2143', valor: 110 },
            { conta: '7777', valor: 390 }
        ]
    },     
];
```

Precisamos totalizar o valor de todos os itens com a conta **2143**. E agora?

## Tentando solucionar com map()

Podemos apelar para a função `map()`, aquela que permite aplicar uma transformação em cada elemento do array resultando em um novo array. Nesse sentido, queremos transformar cada nota iterada em um array de itens que possamos realizar `filter` e `reduce` para filtrar e totalizar respectivamente:

```jsx
// não funciona como esperado! O resultado será 0!
const totalDeUmaConta = 
    notas.map(nota => nota.itens)
        .filter(item => item.conta == '2143')
        .reduce((total, item) => total + item.valor, 0);

console.log(totalDeUmaConta);      
```
Infelizmente o código acima não funciona, porque o resultado de `map()` será multidimensional, ou seja, um array de arrays:

```jsx
// resultado do map
[
    [
        { conta: '2143', valor: 200 },
        { conta: '2111', valor: 500 }
    ],
    [
        { conta: '2222', valor: 120 },
        { conta: '2143', valor: 280 }
    ],
     [
        { conta: '2143', valor: 110 },
        { conta: '7777', valor: 390 }
    ]
]
```

Para que a função filter() funcione como esperado, o array deveria ter uma estrutura inidimensional:

```jsx
// estrutura esperada por filter
[
    { conta: '2143', valor: 200 },
    { conta: '2111', valor: 500 },
    { conta: '2222', valor: 120 },
    { conta: '2143', valor: 280 },
    { conta: '2143', valor: 110 },
    { conta: '7777', valor: 390 }   
]
```
Uma solução é abdicarmos do `map` e utilizarmos `reduce` para achatarmos o array multidimensional em um array de uma dimensão apenas. Vejamos:

```jsx
// Agora sim!

totalDeUmaConta = notas
    .reduce((array, nota) => array.concat(nota.itens), [])
    .filter(item => item.conta == '2143')
    .reduce((total, item) => total + item.valor, 0);
```

Se o leitor compreendeu o motivo pelo qual o primeiro `reduce` foi necessário, já sabe a finalidade do `flatMap`, até porque este reduce está exercendo sua função.

## Uma solução com flatMap()

A função `flatMap()` realiza um map de uma função sobre uma coleção de dados, porém achatando o resultado final em um nível, isto é, retornando um array de uma dimensão apenas.

```jsx
totalDeUmaConta = notas
    .flatMap(nota => nota.itens)
    .filter(item => item.conta === '2143')
    .reduce((total, item) => total + item.valor, 0);

console.log(totalDeUmaConta);
```

## Conclusão

Obrigado por ler! Espero que tenha entendido sobre a utilização de ambos os métodos.