Cinco maneiras interessantes de usar Array.reduce () (e uma maneira chata)

Olá Habr! Apresento a você a tradução do artigo "Cinco maneiras interessantes de usar Array.reduce () (e uma maneira chata)", de Chris Ferdinandi.


De todos os métodos modernos de trabalhar com matrizes, o mais difícil de tudo que eu tinha que usar era Array.reduce ().


À primeira vista, parece ser um método simples e chato que faz pouco. Mas, apesar de sua aparência modesta, Array.reduce () é uma adição poderosa e flexível ao seu conjunto de ferramentas de desenvolvedor.


Hoje, vamos ver algumas coisas interessantes que você pode fazer com Array.reduce ().


Como o Array.reduce () funciona


Os métodos mais modernos de matriz retornam uma nova matriz. O método Array.reduce () é um pouco mais flexível. Ele pode devolver qualquer coisa. Seu objetivo é pegar uma matriz e compactar seu conteúdo em um valor.


Este valor pode ser um número, uma sequência ou até um objeto ou uma nova matriz. Esta é a parte que sempre me confundiu - eu não entendia o quão flexível é!


Sintaxe


Array.reduce () usa dois argumentos: o método de retorno de chamada, executado para iniciar cada elemento na matriz, e o valor inicial initialValue.


O retorno de chamada também recebe dois argumentos: acumulador, que é o valor combinado atual, e o item atual no loop currentValue. Tudo o que você retorna é usado como um acumulador para o próximo elemento no loop. O primeiro loop usa o valor inicial.


var myNewArray = [].reduce(function (accumulator, current) { return accumulator;}, starting); }, starting); 

Vejamos alguns exemplos.


 var myNewArray = [].reduce(function (accumulator, current) { return accumulator;}, starting); 

1. Soma dos números


Suponha que você tenha uma matriz de números que deseja adicionar. Usando Array.forEach (), podemos fazer algo assim:


 var total = 0; [1, 2, 3].forEach(function (num) { total += num; }); 

Este é um exemplo de clichê para usar Array.reduce (). A palavra "acumulador" é confusa; portanto, neste exemplo, a chamaremos de "soma" porque é o que é inerentemente.


 var total = [1, 2, 3].reduce(function (sum, current) { return sum + current; }, 0);    0    . 

No retorno de chamada, adicionamos o valor atual à soma que tem um valor inicial de 0 no primeiro ciclo, depois 1 (valor inicial 0 mais valor do elemento 1), depois 3 (valor total 1 mais valor do elemento 2) e assim por diante.
Um exemplo


2. Uma alternativa para combinar os métodos de matriz Array.map () e Array.filter () em uma única etapa


Imagine que existem muitos magos em Hogwarts.


 var wizards = [ { name: 'Harry Potter', house: 'Gryfindor' }, { name: 'Cedric Diggory', house: 'Hufflepuff' }, { name: 'Tonks', house: 'Hufflepuff' }, { name: 'Ronald Weasley', house: 'Gryfindor' }, { name: 'Hermione Granger', house: 'Gryfindor' }]; 

Queremos criar uma nova matriz que contenha apenas os nomes dos mestres do Hufflepuff. Uma maneira de fazer isso é usar o método Array.filter () para recuperar apenas os assistentes que possuem uma propriedade Hufflepuff em casa. Em seguida, usamos o método Array.map () para criar uma nova matriz contendo apenas a propriedade name para os demais mestres.


 //      var hufflepuff = wizards.filter(function (wizard) { return wizard.house === 'Hufflepuff'; }).map(function (wizard) { return wizard.name; }); 

Usando o método Array.reduce (), você pode obter a mesma matriz em uma passagem, o que melhorará nosso desempenho. Passamos uma matriz vazia ([]) como o valor inicial. A cada passagem, verificamos se wizard.house é uma Lufa-Lufa. Nesse caso, envie-o para newArr (nosso acumulador neste exemplo). Caso contrário, não faça nada.


De qualquer forma, retorne newArr para obter o acumulador na próxima passagem.


 //      var hufflepuff = wizards.reduce(function (newArr, wizard) { if (wizard.house === 'Hufflepuff') { newArr.push(wizard.name); } return newArr; }, []); 

Um exemplo


Criar marcação a partir de uma matriz


E se, em vez de criar uma matriz de nomes, quisermos criar uma lista não ordenada de mestres no Hufflepuff? Em vez de uma matriz vazia em Array.reduce () como nosso valor inicial, passe uma string vazia ('') e chame-a de html.


Se wizard.house for igual a Hufflepuff, combinamos nossa string html com wizard.name agrupado nos elementos da lista de abertura e fechamento (li). Em seguida, retorne o HTML como acumulador no próximo loop.


 //      var hufflepuffList = wizards.reduce(function (html, wizard) { if (wizard.house === 'Hufflepuff') { html += '<li>' + wizard.name + '</li>'; } return html; }, ''); 

Adicione o item de lista desordenado de abertura e fechamento antes e depois de Array.reduce (). Agora você está pronto para adicionar marcação ao DOM.


 //      var hufflepuffList = '<ul>' + wizards.reduce(function (html, wizard) { if (wizard.house === 'Hufflepuff') { html += '<li>' + wizard.name + '</li>'; } return html; }, '') + '</ul>'; 

Um exemplo


4. Agrupando elementos semelhantes em uma matriz


A biblioteca lodash possui um método groupBy () que pega uma coleção de elementos como uma matriz e os agrupa em um objeto com base em alguns critérios.


Digamos que precisamos de uma matriz de números.


Se quisermos agrupar todos os elementos em números pelo valor inteiro, isso deve ser feito usando lodash.


 var numbers = [6.1, 4.2, 6.3]; // returns {'4': [4.2], '6': [6.1, 6.3]} _.groupBy(numbers, Math.floor); 

Se houver uma matriz de palavras e você precisar agrupar os elementos nas palavras pelo comprimento, faríamos isso.


 var words = ['one', 'two', 'three']; // returns {'3': ['one', 'two'], '5': ['three']} _.groupBy(words, 'length'); 

Criando uma função groupBy () usando Array.reduce ()


Você pode recriar a mesma funcionalidade usando o método Array.reduce ().


Criamos uma função auxiliar groupBy (), que utiliza uma matriz e critérios para classificar como argumentos. Dentro de groupBy (), executaremos Array.reduce () para nossa matriz, passando um objeto vazio ({}) como ponto de partida e retornando o resultado.


 var groupBy = function (arr, criteria) { return arr.reduce(function (obj, item) { // Some code will go here... }, {}); }; 

Dentro de Array.reduce (), chamamos a função de retorno de chamada para verificar se o critério é uma função aplicada a um elemento ou uma propriedade de um elemento. Então obtemos seu valor do elemento atual.


Se o objeto ainda não tiver uma propriedade com esse valor, crie-o [property] e atribua uma matriz vazia como seu valor. Por fim, adicione um elemento a essa propriedade e retorne o objeto como um acumulador para o próximo ciclo.


 var groupBy = function (arr, criteria) { return arr.reduce(function (obj, item) { //   ,        //  var key = typeof criteria === 'function' ? criteria(item) : item[criteria]; //    ,  . if (!obj.hasOwnProperty(key)) { obj[key] = []; } //     obj[key].push(item); //      return obj; }, {});}; 

Demonstração de uma função auxiliar concluída.


Agradecimentos especiais a Tom Bremer por sua ajuda. Essa função auxiliar e muito mais podem ser encontradas no Vanilla JS Toolkit .


5. Combinando dados de duas fontes em uma matriz


Lembre-se de nossa lista de assistentes.


 var wizards = [ { name: 'Harry Potter', house: 'Gryfindor' }, { name: 'Cedric Diggory', house: 'Hufflepuff' }, { name: 'Tonks', house: 'Hufflepuff' }, { name: 'Ronald Weasley', house: 'Gryfindor' }, { name: 'Hermione Granger', house: 'Gryfindor' }]; 

E se houvesse um conjunto de dados diferente - um objeto com uma casa e pontos ganhos por cada mágico.


 var points = { HarryPotter: 500, CedricDiggory: 750, RonaldWeasley: 100, HermioneGranger: 1270 }; 

Imagine que queremos combinar os dois conjuntos de dados em uma matriz com o número de pontos adicionados aos dados de cada assistente na matriz de assistentes. Como fazer isso?


O método Array.reduce () é perfeito para isso!


 var wizardsWithPoints = wizards.reduce(function (arr, wizard) { //     points,     // var key = wizard.name.replace(' ', ' '); //     ,  , //   0. if (points[key]) { wizard.points = points[key]; } else { wizard.points = 0; } //   wizard   . arr.push(wizard); //  . return arr; }, []); 

Um exemplo de combinação de dados de duas fontes em uma matriz .


6. Combinando dados de duas fontes em um objeto


E se, em vez disso, for necessário combinar as duas fontes de dados em um objeto no qual o nome de cada assistente seja a chave e a casa e os óculos sejam propriedades? Novamente, o método Array.reduce () é perfeito para isso.


 var wizardsAsAnObject = wizards.reduce(function (obj, wizard) { //      points,     // var key = wizard.name.replace(' ', ' '); //     ,  , //   0. if (points[key]) { wizard.points = points[key]; } else { wizard.points = 0; } //   name delete wizard.name; //   wizard    obj[key] = wizard; //   return obj; }, {}); 

Um exemplo de combinação de dados de duas fontes em um objeto .


Devo usar Array.reduce ()?


O método Array.reduce () evoluiu de sem sentido para o meu método JavaScript favorito. Então vale a pena usá-lo? E quando?


O método Array.reduce () possui um suporte fantástico ao navegador. Ele funciona em todos os navegadores modernos e no IE9. Há muito que é suportado por navegadores móveis. Se precisar de mais, você pode adicionar um polyfill para retornar o suporte no IE6.


O problema mais sério pode ser que o Array.reduce () seja confuso para pessoas que nunca o encontraram [método] antes. A combinação dos métodos Array.filter () com Array.map () é mais lenta e envolve etapas adicionais, mas é mais fácil de ler. Os nomes dos métodos mostram o que eles devem fazer.


Como já mencionado, o método Array.reduce (), em geral, simplifica coisas mais complexas. Um bom exemplo é a função auxiliar groupBy ().


Por fim, essa é outra ferramenta para o seu kit de ferramentas. Uma ferramenta que, se usada corretamente, pode fornecer superpotências.


Sobre o autor


Chris Ferdinandi ajuda as pessoas a aprender baunilha JavaScript. Ele acredita que existe uma maneira mais simples e confiável de fazer as coisas pela Internet.


Chris é o autor da série Vanilla JS Pocket Guide , criador do currículo da Vanilla JS Academy e apresentador do Podcast Vanilla JS . Seu boletim informativo para desenvolvedores é lido por milhares de desenvolvedores todos os dias da semana.


Ele treinou desenvolvedores em organizações como Chobani e Boston Globe, e seus plugins JavaScript foram usados ​​pela Apple e pela Harvard Business School. Chris Coyer, fundador do CSS-Tricks e CodePen, descreveu seu trabalho como "infinitamente citado".


Chris adora piratas, filhotes e filmes da Pixar, e também vive perto de fazendas de cavalos no interior de Massachusetts. Ele lidera o Go Make Things com um filhote de cachorro Bailey.

Source: https://habr.com/ru/post/pt483182/


All Articles