热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

array.reduce_Array.reduce()方法的超能力

array.reduceECMAScript5在2009年引入了许多很棒的功能,其中大多数是数组方法,例如isArray,forEach&

array.reduce

ECMAScript 5在2009年引入了许多很棒的功能 ,其中大多数是数组方法,例如isArray , forEach , map , filter , every , some 。 但是,让我们谈谈我最喜欢的一个: reduce

reduce方法

reduce方法在数组的每个元素上执行reducer回调函数(由用户提供),从而产生单个输出值。

减速器

reducer函数采用四个参数:

  • 累加器(acc)
  • 当前值(当前)
  • 当前索引(idx)
  • 源数组(src)

reducer函数的返回值分配给累加器,累加器的值在整个数组的每次迭代中都会被记住,并最终成为最终的单个结果值。

重要提示:在每次迭代中,您必须   返回下一次迭代的累加器值(最终将是最终的返回值),否则累加器的下一个(最终是最终的)值将undefined

初始值

reduce方法采用第二个可选参数: initialValue
如果未提供,则累加器的初始值将是数组的第一个元素,并且第一次迭代将指向第二个元素。 如果initialValue   提供时,它将是累加器的初始值,并且第一次迭代将指向数组的第一个元素。

例子

有或没有初始值的数字求和

const numbers = [ 1 , 2 , 3 ];// Without initialValue
const sum = numbers.reduce(( accumulator, currentValue ) => accumulator + currentValue
);// Prints 6
console .log(sum);// With initialValue
const initialValue = 3 ;
const sumWithInitialValue = numbers.reduce(( accumulator, currentValue ) => accumulator + currentValue
, initialValue);// Prints 9
console .log(sumWithInitialValue);

如果没有初始值,则第一次迭代将使accumulator指向数组的第一个元素(1),而currentValue指向数组的第二个元素(2)。

给定初始值,第一次迭代将具有一个具有给定初始值(3)的值的accumulator ,而currentValue将指向数组的第一个元素(1)。

计算数组中的出现次数

让我们计算以下单词的出现次数,并将结果存储在地图中:

土拨鼠卡盘要多少木头
如果土拨鼠能夹木头?
他会努力,他会尽可能
和土拨鼠一样多
如果土拨鼠可以夹木头。

const sentence = "how much wood would a woodchuck chuck" +"if a woodchuck could chuck wood " +"he would chuck he would as much as he could " +"and chuck as much as a woodchuck would " +"if a woodchuck could chuck wood" ;const words = sentence.split( " " );const occurencesMap = words.reduce(( occurences, word ) => {const numOfOccurences = (occurences.get(word) || 0 ) + 1 ;occurences.set(word, numOfOccurences);return occurences;}
, new Map ());const numOfWoodchucks = occurencesMap.get( "woodchuck" );// 4
console .log(numOfWoodchucks);

我们初始化一个空的映射并将其用作累加器的初始值,在迭代句子中的单词时初始化或更新每个单词的出现次数。

这只是两个例子,但是现在您必须已经意识到reduce是多么的出色,对吗?

它允许您采用数组并将其值减小为基本上可以从其保存的数据派生的任何值。 它还允许您返回任何类型的数据,而与数组元素的类型无关。

一种统治所有人的方法?

回顾其他ES5数组方法,我们可以看到每个方法在数组上使用给定的回调函数并返回某种结果。

例如:

  • map转换数组的每个元素,并返回一个新的   数组。
  • every检查给定条件是否适用于数组中的每个元素,并返回相应的布尔值。

看起来很熟悉吧?

使用我们已经知道的知识,让我们尝试使用reduce来实现其他ES5数组方法。

注意:在每个示例中,我们都会将新方法添加到Array的原型中, this将指向我们正在操作的数组。

地图

map()方法创建一个新数组,其中每个原始元素都由给定的transformer回调进行transformer

用法

const array = [ 1 , 2 , 3 ];
const doubled = array.map( num => num * 2 );// Prints [2, 4, 6]
console .log(doubled);

使用将数组中每个数字加倍的转换器回调,我们得到一个新数组,其中每个元素都是其原始值的两倍。

reduce

map在一个数组map操作并返回一个新数组,因此累加器必须是一个数组。

Array .prototype.mapWithReduce = function ( transformer ) {return this .reduce( ( newArray, currentElement ) => {const newElement = transformer(currentElement);newArray.push(newElement);return newArray;}, []);
}const array = [ 1 , 2 , 3 ];
const doubled = array.mapWithReduce( num => num * 2 );// Prints [2, 4, 6]
console .log(doubled);

使用reduce ,我们从一个空的数组累加器开始,然后遍历该数组。 然后,我们将转换器回调应用于每个元素,并将其推入累加数组。

过滤

filter()方法创建一个新数组   通过提供的功能实现的所有通过测试的元素。

用法

const array = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ];
const evenOnly = array.filter( num => num % 2 === 0 );// Prints [2, 4, 6, 8, 10]
console .log(evenOnly);

使用测试回调过滤掉所有奇数,我们得到一个包含原始数组所有偶数元素的新数组。

reduce

就像前面的示例一样,filter也在数组上操作并返回一个新数组,因此累加器必须是数组。

Array .prototype.filterWithReduce = function ( tester ) {return this .reduce( ( newArray, currentElement ) => {if (tester(currentElement)) {newArray.push(currentElement);};return newArray;}, []);
}const array = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ];
const evenOnly = array.filterWithReduce( num => num % 2 === 0 );// Prints [2, 4, 6, 8, 10]
console .log(evenOnly);

使用reduce ,我们从一个空的数组累加器开始,然后遍历该数组。 然后,我们使用测试器回调检查是否应将每个元素都推到累积数组中。

每一个

every()方法测试数组中的所有元素是否通过提供的函数实现的测试。 它返回一个布尔值。

用法

const array = [ 1 , 2 , 3 , 4 , 5 ];
const result &#61; array.every( num &#61;> num <10 );// Prints true
console .log(result);

使用回调函数测试数组中的每个元素&#xff0c;我们得到一个布尔值&#xff0c;指示所有元素是否通过测试。 在这种情况下&#xff0c;所有元素都小于10&#xff0c;因此every元素都返回true

reduce

every运算符都对数组进行运算并返回布尔值&#xff0c;因此累加器必须为布尔值。

Array .prototype.everyWithReduce &#61; function ( tester ) {return this .reduce( ( acc, currentElement ) &#61;>acc && tester(currentElement), true );
}const array &#61; [ 1 , 2 , 3 , 4 , 5 ];
const result &#61; array.everyWithReduce( num &#61;> num <10 );// Prints true
console .log(result);

使用reduce &#xff0c;我们从布尔累加器值为true &#xff08;稍后将讨论原因&#xff09;并遍历数组。 然后&#xff0c;我们使用逻辑AND&#xff08; && &#xff09;将测试器回调的结果链接到累加器&#xff0c;以在所有元素均通过测试时最终返回true &#xff0c; otherwise返回false。

为什么从true开始&#xff1f;

如果数组为空&#xff0c;则无论测试回调如何&#xff0c; every返回true &#xff08;即使该回调返回false &#xff09;。

否则&#xff0c;如果所有元素都满足条件&#xff0c;则使用逻辑AND链接初始true值最终将解析为true 。 否则&#xff0c;链接最终将解析为false

一些

some&#xff08;&#xff09;方法测试数组中的至少一个元素是否通过了由提供的函数实现的测试。 它返回一个布尔值。

用法

const array &#61; [ 1 , 2 , 3 , 4 , 5 ];
const result &#61; array.some( num &#61;> num > 3 );// Prints true
console .log(result);

使用回调函数测试数组中的每个元素&#xff0c;我们得到一个布尔值&#xff0c;指示是否有任何元素通过测试。 在这种情况下&#xff0c;第四个元素大于3&#xff0c;因此some元素返回true

reduce

some对数组进行运算并返回布尔值&#xff0c;因此累加器必须为布尔值。

Array .prototype.someWithReduce &#61; function ( tester ) {return this .reduce( ( acc, currentElement ) &#61;>acc || tester(currentElement), false );
}const array &#61; [ 1 , 2 , 3 , 4 , 5 ];
const result &#61; array.someWithReduce( num &#61;> num > 3 );// Prints true
console .log(result);

使用reduce &#xff0c;我们从布尔累加器值false &#xff08;稍后将讨论原因&#xff09;&#xff0c;然后遍历数组。 然后&#xff0c;我们使用逻辑OR&#xff08; || &#xff09;将测试器回调的结果链接到累加器&#xff0c;以在任何元素通过测试时最终返回true &#xff0c;否则返回false

为什么从false开始&#xff1f;

如果数组为空&#xff0c;则无论测试回调如何&#xff0c;即使返回回调true &#xff0c; some返回false

否则&#xff0c;如果任何元素满足条件&#xff0c;则使用逻辑OR链接初始false值最终将解析为true 。 否则&#xff0c;链接最终将解析为false

免责声明&#xff08;每部分&#xff09;

every方法都会对数组中存在的每个元素执行一次提供的回调函数&#xff0c;直到找到回调返回虚假值&#xff08;转换为布尔值时该值为false &#xff09;的那个函数为止。 如果找到这样的元素&#xff0c;则every元素立即返回false

类似地&#xff0c; some &#xff0c;直到它找到地方回调返回truthy值&#xff08;即变成值的一个方法执行一次为每个存在于阵列中元件的回调函数true时转换成布尔&#xff09;。 如果找到了这样的元素&#xff0c;则some元素会立即返回true

但是&#xff0c;没有终止 reduce漂亮方法 中间循环 。
这意味着虽然两个实现&#xff08;原始的every/some方法以及使用reduce的相应实现&#xff09;的运行时均为O(n) &#xff0c;但原始实现很可能会终止而无需遍历整个数组&#xff0c;从而使它们更有效。

筛选器&#43;地图

给定一个数字数组&#xff0c;最有效的方法是过滤出所有偶数元素并将其余的元素平方&#xff08;使用ES5方法&#xff09;&#xff1f;

让我们先尝试filter然后再尝试map &#xff1a;

const array &#61; [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ];const tester &#61; num &#61;> num % 2 &#61;&#61;&#61; 1 ;
const transformer &#61; num &#61;> num * num;const result &#61; array.filter(tester).map(transformer);// Prints [1, 9, 25, 49, 81]
console .log(result);

我们创建一个仅保留奇数元素的测试器函数和一个将给定元素平方的变压器函数。 然后在链接filtermap方法时使用这两个回调函数&#xff0c;并返回所需的数组。

让我们用我们了解的通过reduce实现filtermap &#xff0c;只有这次我们将它们一次组合起来。

const array &#61; [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ];const tester &#61; num &#61;> num % 2 &#61;&#61;&#61; 1 ;
const transformer &#61; num &#61;> num * num;const result &#61; array.reduce( ( newArray, currentElement ) &#61;> {if (tester(currentElement)) {const newElement &#61; transformer(currentElement);newArray.push(newElement); }return newArray;
}, []);// Prints [1, 9, 25, 49, 81]
console .log(result);

我们使用相同的测试器和转换器函数来测试每个元素是否应保留在数组中&#xff0c;并对其进行转换。

这种方法省去了创建过滤值中间数组的需要&#xff0c;并且由于不必迭代两个不同的数组&#xff08;原始数组和中间数组&#xff09;&#xff0c;我们得到了一种效率更高的算法。

结论

这些是如何使用功能强大的reduce方法实现其他ES5方法的一些示例。

您如何在日常编码中使用它&#xff1f; 分享评论&#xff01;

资料来源
  • w3schools的ES5功能
  • MDN Web文档提供的Javascript数组方法 。
    本文中的每个方法文档均来自此处。

翻译自: https://hackernoon.com/the-superpowers-of-arrayreduce-jn1536p6

array.reduce



推荐阅读
  • 重要知识点有:函数参数默许值、盈余参数、扩大运算符、new.target属性、块级函数、箭头函数以及尾挪用优化《深切明白ES6》笔记目次函数的默许参数在ES5中,我们给函数传参数, ... [详细]
  • 本文将继续探讨 JavaScript 函数式编程的高级技巧及其实际应用。通过一个具体的寻路算法示例,我们将深入分析如何利用函数式编程的思想解决复杂问题。示例中,节点之间的连线代表路径,连线上的数字表示两点间的距离。我们将详细讲解如何通过递归和高阶函数等技术实现高效的寻路算法。 ... [详细]
  • 浅析python实现布隆过滤器及Redis中的缓存穿透原理_python
    本文带你了解了位图的实现,布隆过滤器的原理及Python中的使用,以及布隆过滤器如何应对Redis中的缓存穿透,相信你对布隆过滤 ... [详细]
  • 开发日志:高效图片压缩与上传技术解析 ... [详细]
  • 技术分享:使用 Flask、AngularJS 和 Jinja2 构建高效前后端交互系统
    技术分享:使用 Flask、AngularJS 和 Jinja2 构建高效前后端交互系统 ... [详细]
  • 本指南从零开始介绍Scala编程语言的基础知识,重点讲解了Scala解释器REPL(读取-求值-打印-循环)的使用方法。REPL是Scala开发中的重要工具,能够帮助初学者快速理解和实践Scala的基本语法和特性。通过详细的示例和练习,读者将能够熟练掌握Scala的基础概念和编程技巧。 ... [详细]
  • 多线程基础概览
    本文探讨了多线程的起源及其在现代编程中的重要性。线程的引入是为了增强进程的稳定性,确保一个进程的崩溃不会影响其他进程。而进程的存在则是为了保障操作系统的稳定运行,防止单一应用程序的错误导致整个系统的崩溃。线程作为进程的逻辑单元,多个线程共享同一CPU,需要合理调度以避免资源竞争。 ... [详细]
  • 解决Bootstrap DataTable Ajax请求重复问题
    在最近的一个项目中,我们使用了JQuery DataTable进行数据展示,虽然使用起来非常方便,但在测试过程中发现了一个问题:当查询条件改变时,有时查询结果的数据不正确。通过FireBug调试发现,点击搜索按钮时,会发送两次Ajax请求,一次是原条件的请求,一次是新条件的请求。 ... [详细]
  • 深入解析Struts、Spring与Hibernate三大框架的面试要点与技巧 ... [详细]
  • 如何使用 `org.apache.tomcat.websocket.server.WsServerContainer.findMapping()` 方法及其代码示例解析 ... [详细]
  • 在处理大规模数据数组时,优化分页组件对于提高页面加载速度和用户体验至关重要。本文探讨了如何通过高效的分页策略,减少数据渲染的负担,提升应用性能。具体方法包括懒加载、虚拟滚动和数据预取等技术,这些技术能够显著降低内存占用和提升响应速度。通过实际案例分析,展示了这些优化措施的有效性和可行性。 ... [详细]
  • Android 构建基础流程详解
    Android 构建基础流程详解 ... [详细]
  • 在ElasticStack日志监控系统中,Logstash编码插件自5.0版本起进行了重大改进。插件被独立拆分为gem包,每个插件可以单独进行更新和维护,无需依赖Logstash的整体升级。这不仅提高了系统的灵活性和可维护性,还简化了插件的管理和部署过程。本文将详细介绍这些编码插件的功能、配置方法,并通过实际生产环境中的应用案例,展示其在日志处理和监控中的高效性和可靠性。 ... [详细]
  • 使用 Vuex 管理表单状态:当输入框失去焦点时自动恢复初始值 ... [详细]
  • 本文深入探讨了C#中的反射与特性功能。首先,介绍了反射的基本概念,即通过元数据(包括类的方法、属性和字段等)在运行时动态获取和操作程序信息的能力。此外,还详细解析了特性的使用方法及其在代码注解和元数据扩展中的重要作用,为开发者提供了丰富的编程技巧和实践指导。 ... [详细]
author-avatar
技术小白
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有