Map x flatMap, entendendo a diferença na prática

trinity_

Ivan Trindade

Posted on January 5, 2023

Map x flatMap, entendendo a diferença na prática

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.

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 }
        ]
    },     
];
Enter fullscreen mode Exit fullscreen mode

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:

// 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);      
Enter fullscreen mode Exit fullscreen mode

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

// 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 }
    ]
]
Enter fullscreen mode Exit fullscreen mode

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

// 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 }   
]
Enter fullscreen mode Exit fullscreen mode

Uma solução é abdicarmos do map e utilizarmos reduce para achatarmos o array multidimensional em um array de uma dimensão apenas. Vejamos:

// Agora sim!

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

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.

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

console.log(totalDeUmaConta);
Enter fullscreen mode Exit fullscreen mode

Conclusão

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

💖 💪 🙅 🚩
trinity_
Ivan Trindade

Posted on January 5, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related