文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

深入浅出数组reduce,看完就会

2024-12-01 13:55

关注

reduce

reduce() 方法对数组中的每个元素按序执行一个由您提供的 reducer 函数,每一次运行 reducer 会将先前元素的计算结果作为参数传入,最后将其结果汇总为单个返回值。,这是官方MDN上给的一段话。

每次将会把前一次的计算结果当成下次的参数传入,什么意思?

我们看一下简单的例子;

const sum = (arr) => {
return arr.reduce((prev, cur) => {
return prev + cur
}, 0)
}
console.log('sum: ', sum([1,2,3,4,5])) // 15

结果是15,嘿,这个sum就是这么简单吗?我们看下之前是怎么写的;

const sum2 = (arr) => {
let ret = 0;
arr.forEach(val => {
ret+=val;
})
return ret
}
console.log('sum2:', sum2([1,2,3,4,5])) // 15

我们发现在之前我们的做法是循环计算,reduce的方式比循环方式代码要简单得多,但是并不是像循环方式一样那么通俗易懂,具体我们断点分析一下;

const sum = (arr) => {
return arr.reduce((prev, cur) => {
debugger;
return prev + cur
}, 0)
}
console.log('sum: ', sum([1,2,3,4,5])) // 15

首次:

其实我们发现,​reduce​回调函数内,第一个参数prev​默认就是初始值传入的0​,然后cur就是每次循环数组的当前值。

第一次:prev:0, cur: 1,执行返回结果0+1,为第二次循环的初始值prev:1。

第二次:prev:1, cur:2,执行返回结果1+2,为第三次循环的初始值prev:3。

...

第五次:prev:10, cur:5,执行返回结果10+5,结束。

所以我们始终记住这个万能公式就行,prev首次是默认传入的值,当循环迭代下一次循环时,会将上一次返回的结果作为prev,cur永远是当前迭代的item。

var arr = [];
const callback = (prev, current, currentIndex, source) => {
// 首次prev = init, 后面每次计算后结果作为下一次的prev,current是当前arr的item
// current: 当前的数组的item
// currentIndex: 当前索引
// source 原数组,也是arr
}
arr.reduce(callback, init?)

注意init是可选的,如果有值,则prev默认取它,那么current就取默认第一个值,如果init没有值,那么prev就是第一个,current就是第二值,你会发现不给默认值,比给默认值少了一次循环。

const sum = (arr) => {
return arr.reduce((prev, cur, curentIndex, arr) => {
console.log(prev, cur, curentIndex, arr)
return prev + cur
})
}
console.log('sum: ',sum([1,2,3,4,5])) // 15
// 1 2 1 [1, 2, 3, 4, 5]
// 3 3 2 [1, 2, 3, 4, 5]
// 6 4 3 [1, 2, 3, 4, 5]
// 10 5 4 [1, 2, 3, 4, 5]

过滤数据中指定字段数据;

用reduce过滤指定需要的字段;

let sourceArr = [
{id: 1, name: 'Web技术学苑', age: 18},
{id: 2, name: 'Maic', age: 20},
{id: 3, name: 'Tom', age: 16},
]
const ret = sourceArr.reduce((prev, cur) => {
const {id, age} = cur;
return prev.concat({id, age})
}, [])
console.log(ret);
// [ { id: 1, age: 18 }, { id: 2, age: 20 }, { id: 3, age: 16 } ]

如果是用map大概就是下面这样的了。

...
const ret2 = sourceArr.map(v => {
return { id: v.id, age: v.age }
})
console.log('ret2', ret2);

多维数组打平,二维转一维;

reduce是下面这样的;

const sourceArr2 = [[1,2,3], [4,5,6], [8,9], 0]
const ret3 = sourceArr2.reduce((prev, cur) => {
return prev.concat(cur)
}, [])

以前你可能会这样的;

...
const ret4 = sourceArr2.flat(1)

或者用递归方式;

var flatLoop = (source, ret = []) => {
const loop = (arr) => {
arr.forEach(v => {
if (Array.isArray(v)) {
loop(v)
} else {
ret.push(v)
}
})
}
loop(source)
return ret
}
flatLoop(sourceArr2, [])

统计一个字符出现的次数;

forEach版本;

const strCount = (arr) => {
const obj = {}
arr.forEach(key => {
if (key in obj) {
obj[key]+=1;
} else {
obj[key]=1;
}
});
return obj
}
const ret5 = strCount(['a', 'a', 'b', 'c', 'd'])
console.log('ret5', ret5)
// ret5 {a: 2, b: 1, c: 1, d: 1}

reduce版本实现;

const strCount2 = (arr) => {
return arr.reduce((prev, cur) => {
if (cur in prev) {
prev[cur]+=1;
} else {
prev[cur] = 1;
}
return prev
}, {})
}
console.log('ret6', strCount2(['a', 'a', 'b', 'c', 'd']))

获取数组中某个字段的所有集合;

var publicInfo = [
{
id: '1',
name: 'Web技术学苑',
age: 8
},
{
id: '2',
name: '前端从进阶到入院',
age: 10
},
{
id: '3',
name: '前端之神',
age: 15
},
{
id: '3',
name: '前端之巅',
age: 12
}
]
const ret7 = publicInfo.map(v => v.name)
console.log('ret7', ret7)

reduce实现;

const ret8 = publicInfo.reduce((prev, cur) => {
return prev.concat(cur.name)
}, [])
console.log('ret8', ret8)

数据去重;

以前你可以用Set或者循环去做的

const sourceData = ['1','1', '2', 3,4,5,3]
console.log([...new Set(sourceData)]) // ['1','2',3,4,5]
// or
const obj = {}
sourceData.forEach(item => {
obj[item] = item
})
console.log(Object.values(obj))

reduce实现去重。

...
consy ret9 = sourceData.reduce((prev, cur) => {
if (prev.indexOf(cur) === -1) {
prev.push(cur)
}
return prev
}, [])

代替filter与map

假设我们有一个场景,就是在原数据中过滤找出age>10大于的数据并返回对应的name。

var publicInfo = [
{
id: '1',
name: 'Web技术学苑',
age: 10
},
{
id: '2',
name: '前端从进阶到入院',
age: 10
},
{
id: '3',
name: '前端之神',
age: 12
},
{
id: '3',
name: '前端之巅',
age: 12
}
]
const ret11 = publicInfo.filter(v => v.age >10).map(v => v.name);
console.log(ret11); // ['前端之神', '前端之巅']

我们知道上面使用filter与map有两次循环,但是reduce就可以做到仅一次循环就可以搞定。

...
publicInfo.reduce((prev, cur) => {
if (cur.age > 10) {
prev.push(cur.name)
}
return prev
}, [])

关于reduce[1]更多的实践可以参考MDN文档,在项目中更多的实践以后再一一补充。

总结

主要分析了reduce这个计算方法特性,每次计算的结果会当成下一次的prev的初始值,第二个参数``cur`是当前循环数组的值。

如果reduce给了初始值,那么prev是就是当前传入的初始值,如果没有初始值,则默认就是当前数组的首项,cur就是第二元素,默认没有初始值会比给初始值少一次循环。

以reduce实践了一些例子,夯实reduce的一些用法特性。

本文示例源码code example[2]。

参考资料

[1]reduce: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

[2]code example: https://github.com/maicFir/lessonNote/tree/master/javascript/22-reduce

来源:Web技术学苑内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯