文章目录

  • 参考
  • 快速入门
    • 语法
    • 参数说明
    • 例子——数组求和
      • callback 被调用四次,每次调用的参数和返回值如下表
      • 例子——计算数组中每个元素出现的次数
      • 例子——数组去重
      • 例子——将二维数组转化为一维
      • 例子——将多维数组转化为一维
      • 例子——对象里的属性求和
  • reduce函数有什么优势?
    • 案例需求说明:
    • 解决办法 —— 函数式编程
    • 解决办法 —— 那reduce函数就是为我们而来——**`减少数组迭代次数`**
      • 链式调用分析
      • 大数据场景分析
      • 让我们分解来看发生了什么?
      • 减少迭代次数有什么好处呢?

参考

  1. Array.reduce()方法解析
  2. 减少你对Array.reduce()的恐惧!
  3. JS数组reduce()方法详解及高级技巧

快速入门

语法

array.reduce(function(accumulator, currentValue, currentIndex, array), initialValue)

参数说明

  1. 第一个参数是function

    • accumulator:上一次调用回调返回的值,或者是提供的初始值(initialValue)
    • currentValue:数组中正在处理的元素
    • currentIndex:数据中正在处理的元素索引,如果提供了 initialValue ,从0开始;否则从1开始
    • array: 调用 reduce 的数组
  2. 第二个参数是初始化值(第一次循环的accumulator值)
    可选项,其值用于第一次调用 callback 的第一个参数。如果没有设置初始值,则将数组中的第一个元素作为初始值

例子——数组求和

// 初始化数组
var numbers = [0, 1, 2, 3, 4
]
// accumulator:上一次调用回调返回的值,或者是提供的初始值(initialValue)
// currentValue:数组中正在处理的元素
// currentIndex:数据中正在处理的元素索引,如果提供了 initialValue ,从0开始;否则从1开始
// array: 调用 reduce 的数组
let result = numbers.reduce((accumulator, currentValue, currentIndex, array) => {return accumulator + currentValue;
});console.log(result) // 10

第一次循环的时候,由于没有设置初始化的值,则accumulator第一次的值为numbers[0], 索引currentIndex是从第1个数字开始(数组是从0开始计算)

callback 被调用四次,每次调用的参数和返回值如下表

callback accumulator currentValue currentIndex array return value
first call 0 1 1 [0,1,2,3,4] 1
second call 1 2 2 [0,1,2,3,4] 3
third call 3 3 3 [0,1,2,3,4] 6
fourth call 6 4 4 [0,1,2,3,4] 10

例子——计算数组中每个元素出现的次数

let names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];let nameNum = names.reduce((pre,cur)=>{if(cur in pre){pre[cur]++}else{pre[cur] = 1 }return pre
},{})
console.log(nameNum); //{Alice: 2, Bob: 1, Tiff: 1, Bruce: 1}

例子——数组去重

let arr = [1,2,3,4,4,1]
let newArr = arr.reduce((pre,cur)=>{if(!pre.includes(cur)){return pre.concat(cur)}else{return pre}
},[])
console.log(newArr);// [1, 2, 3, 4]

例子——将二维数组转化为一维

let arr = [[0, 1], [2, 3], [4, 5]]
let newArr = arr.reduce((pre,cur)=>{return pre.concat(cur)
},[])
console.log(newArr); // [0, 1, 2, 3, 4, 5]

例子——将多维数组转化为一维

let arr = [[0, 1], [2, 3], [4,[5,6,7]]]
const newArr = function(arr){return arr.reduce((pre,cur)=>pre.concat(Array.isArray(cur)?newArr(cur):cur),[])
}
console.log(newArr(arr)); //[0, 1, 2, 3, 4, 5, 6, 7]

例子——对象里的属性求和

var result = [{subject: 'math',score: 10},{subject: 'chinese',score: 20},{subject: 'english',score: 30}
];var sum = result.reduce(function(prev, cur) {return cur.score + prev;
}, 0);
console.log(sum) //60

reduce函数有什么优势?

案例需求说明:

我们有这样一组Users数据,要对数据做如下处理

  1. 需要一个新的具有所有user全称的数组(它的姓 + ‘ ‘ + 它的名),
  2. 要求user年龄在20岁
  3. 全称的名字超过10个字母
const users = [{firstName: 'Bob',lastName: 'Doe',age: 37,}, {firstName: 'Rita',lastName: 'Smith',age: 21,}, {firstName: 'Rick',lastName: 'Fish',age: 28,}, {firstName: 'Betty',lastName: 'Bird',age: 44,}, {firstName: 'Joe',lastName: 'Grover',age: 22,}, {firstName: 'Jill',lastName: 'Pill',age: 19,}, {firstName: 'Sam',lastName: 'Smith',age: 22,}//  模拟一个简单的列表数据
];

解决办法 —— 函数式编程

const twentySomethingsLongFullNames = users//  首先我们过滤初年龄在20岁的人.filter(user => user.age >= 20 && user.age < 30)//  然后将每一项的名和姓拼接到一起.map(user => `${user.firstName} ${user.lastName}`)//  最后过滤掉全名字符数小于9的.filter(fullName => fullName.length >= 10);

或许你想独立的测试这些函数,那让我们将功能函数抽象出来,让它变得更具有可读性

const isInTwenties = user => user.age >= 20 && user.age < 30;
const makeFullName = user => `${user.firstName} ${user.lastName}`;
const isAtLeastTenChars = fullName => fullName.length >= 10;const twentySomethingsLongFullNames = users.filter(isInTwenties).map(makeFullName).filter(isAtLeastTenChars);

优点:以这种方式处理这个问题非常优雅,并且对于数据少的数组,这绝对是我推荐去处理解决问题的方式。每个函数都可以被独立测试,这种写法真的很不错。

缺点:同样重要的是这不是唯一的方式去完成这个功能,当你遇到相当大规模的数据,处理这样的问题时,考虑其他的方式可能是更好的。

解决办法 —— 那reduce函数就是为我们而来——减少数组迭代次数

链式调用分析

在上述提供的方法中,我们总共遍历了3次数组(更确切的说,每运行一个函数都会返回一个修改后的数组)。现在面对大多数情况,这么做是可以的,因为通常我们不会去处理大量的数据,所以用几次遍历可能它也不会花费很长时间去执行它们。
在链式调用里,每一次使用filter,可能会返回一个更小的数组,所以遍历时,它不会像原始数组那么长。但它仍然不是理想的方式去减少迭代次数。

大数据场景分析

假如我们开发的应用非常成功,并且我们将要处理类似于Google/Facebook/Hooli这种大规模的数据。在这种情况下,我们想要减少过多的运算数量。当三次遍历数组完成的事情我们可以一次遍历解。那对我们来说,这一定是显著的性能优化。
让我们给出一个例子,在这个例子中,我们使用reduce函数,而且使用上面命名过的三个函数(因为我们已经为它们写过测试,并且我们不想重写或者移除它们)

const isInTwenties = user => user.age >= 20 && user.age < 30;
const makeFullName = user => `${user.firstName} ${user.lastName}`;
const isAtLeastTenChars = fullName => fullName.length >= 10;const twentySomethingsLongFullNames = users.reduce(//  第一个参数是我们的reducer函数 (accumulator, user) => {const fullName = makeFullName(user);if (isInTwenties(user) && isAtLeastTenChars(fullName)) {accumulator.push(fullName);}//  Always return the accumulator (for the next iteration)return accumulator},//  第二个参数(可选)是初始值[]
);

让我们分解来看发生了什么?

reduce函数接受两个参数,第一个是我们的reducer回调函数,第二个是初始值
然后reducer回调函数本身接受几个参数:

  • 第一个参数是accumulator累加器
  • 第二个是数组中的item
  • 第三个参数是该项的索引
  • 最后一个参数是原始数组的引用

accumulator累加器是在你操作数组时需要积累的值。当reducer函数在数组第一项上运行时,初始值参数会被赋值给accumulator。如果你没有提供一个初始值,reduce实际上是从index==1的项(数组的第二项)开始运行,此accumulator累加器的值将会是数组的第一项。

我喜欢reduce的原因就像它的名字一样介绍了它做了什么–你想要reduce一个数组进而从数组中得到你想要的数据。在我们的例子中,我们想要的结果是一个新的数组(具有全称的users数组)。但是你使用reduce的结果不一定必须是另一个数组。你可以reduce生成一个新的对象,一个原始的类型,例如一个bool值,一个数字,或者是任何你想要的一个值。

减少迭代次数有什么好处呢?

在例子中,你可能会好奇我在前文提及到的性能。我测试了这个通过生成一个巨大的users数组(100000个元素)。然后我做了粗滤的 console.time 去检查链式调用三个函数与使用reduce函数一次遍历哪个是更快的。正如期待的那样,一次遍历的结果是很快的(至少快了三倍)
再一次强调,一次便利的版本并不是绝对的更好的选择,因为filter-map-filter的版本是更具有可读性的。但是如果你是那种可以在尽可能写出具有优秀性能的代码中获得乐趣的程序员,又或者如果你注意到你的App在大规模数据中有点慢,也许在大数据的情况下减少遍历次数是值得的。

  1. 大数据适用于Array.reduce()
  2. 过滤器链代码的可读性更高

Array.reduce函数学习(适用大数据)相关推荐

  1. 资源 | AI、神经网络、机器学习、深度学习以及大数据学习备忘单

    向AI转型的程序员都关注了这个号☝☝☝ 以下是关于神经网络.机器学习.深度学习以及大数据学习的备忘单,其中部分内容和此前发布的<资源 | 值得收藏的 27 个机器学习的小抄>有所重复,大家 ...

  2. Python之GUI:基于Python的GUI界面设计的一套AI课程学习(机器学习、深度学习、大数据、云计算等)推荐系统(包括语音生成、识别等前沿黑科技)

    Python之GUI:基于Python的GUI界面设计的一套AI课程学习(机器学习.深度学习.大数据.云计算等)推荐系统(包括语音生成.识别等前沿黑科技) 导读 基于Python的GUI界面设计的一套 ...

  3. 大数据开发学习,大数据学习路线(完整详细版)

    很多初学者,对大数据的概念都是模糊不清的,大数据是什么,能做什么,学的时候,该按照什么线路去学习,学完往哪方面发展,想深入了解,想学习的同学欢迎加入大数据学习qq群:199427210,有大量干货(零 ...

  4. 大数据怎么学习:大数据学习的关键技术知识体系、学习路径和误区

    由于大数据技术涉及内容太庞杂,大数据应用领域广泛,而且各领域和方向采用的关键技术差异性也会较大,难以三言两语说清楚,本文从数据科学和大数据关键技术体系角度,来说说大数据的核心技术什么,到底要怎么学习它 ...

  5. 新手如何学习云计算大数据,云计算的学习路线

    如今云计算火的一塌糊涂,不管你是男生还是女生就业前景摆在那里,只要你有技术有能力,前景不可限量,所以,不要担心就业前景的问题,要担心就担心你自己的能力问题.只有你真正的掌握了技术,才能有更好的就业发展 ...

  6. 深度学习 vs. 大数据:神经网络权值的版权属于谁?

     深度学习 vs. 大数据:神经网络权值的版权属于谁? width="22" height="16" src="http://hits.sinaj ...

  7. 量化学习:大数据时代的学习方式

    摘 要:未来人工智能.大数据.学习分析等技术被广泛应用于教育教学中,量化学习将成为新的研究热点.本研究首先对量化学习的内涵.特征.工具和方法进行概述,然后阐述了量化学习的价值意义和应用案例,进而分析了 ...

  8. 深度学习和大数据之间,主要是什么关系?

    1)深度学习(Deep Learning)只是机器学习(Machine Learning)的一种类别,一个子领域.机器学习 > 深度学习 2)大数据(Big Data)不是具体的方法,甚至不算具 ...

  9. 四位顶级AI大牛纵论:深度学习和大数据结合的红利还能持续多久?

    这轮 AI 热潮的很大一个特点就是底层技术方面在打通,虽然说过去对通用人工智能大家曾经有过很高的期望,但一直没有落地.这次,深度学习给大家带来了很多机会,使得我们在底层技术方面有了越来越多的共性.然而 ...

最新文章

  1. 错误:无法作为数据库主体执行,因为主体 dbo 不存在、无法模拟这种类型的主体,或您没有所需的权限...
  2. linux下查看当前用户的 三个命令
  3. AI:神经网络调参(数据、层数、batch大小,学习率+激活函数+正则化+分类/回归)并进行结果可视化
  4. kali Linux 源更新
  5. 南理工计算机博士 年薪_计算机专业的女博士毕业后,进入211大学当讲师,年薪曝光...
  6. Java GregorianCalendar computeTime()方法与示例
  7. java hibernate 多对多_java - hibernate多对多问题
  8. 跳转语句_javascript流程语句(单分支)
  9. onenote设置默认新建页面颜色非白色
  10. 硬笔行书字帖3500常用字_2018年【成年人实用硬笔行书】一对一直播培训简介
  11. VFP 常用 OCX 控件 注册
  12. 想知道raw转换jpg软件怎么用?教你raw转换的方法
  13. Elasticsearch核心知识点大全
  14. 解决undefined reference to `WinMain'
  15. 把list集合转换为JSON
  16. 电商数据抓取的几种方式分享-开发平台接口、网络爬虫数据、数据挖掘
  17. 苏州IT/互联网交流群
  18. 近段时间的学习碎片整理(10)
  19. 撤销Dropbox修改,恢复Dropbox误删及覆盖的文件
  20. SCP测试服务器的上行/下行带宽

热门文章

  1. 电动车防盗器语音芯片方案——NV020C 直推0.5w喇叭
  2. Code - Windows Overlapped
  3. 【哈希表】554. 砖墙
  4. 2016MUTC9-1010 Jong Hyok and String
  5. 3dMax利用粒子流创建烟花效果详细教程
  6. 多迪技术总监揭秘:Java入门最佳学习路径几个阶段?
  7. 如何在html网页中插入视频(以及让视频自动播放的问题)
  8. python左闭右开区间_程序设计中左闭右开区间的广泛应用
  9. java.util.List.subList ,开区间和闭区间
  10. C ++ 经典 兔子问题