数组扁平化与reduce()方法详解及高级技巧

📝 个人简介

⭐ 个人主页:我是段段🙋‍
🍊 博客领域:编程基础、前端💻
🍅 写作风格:干货!干货!都是干货!
🍑 精选专栏:数组
🛸 支持段段:点赞👍、收藏⭐、留言💬

在学习数组扁平化之前,先了解一下reduce()方法~~ QoQ

reduce()方法及高级技巧

reduce()方法接收一个函数作为累加器,数组中的每个值(从左向右)开始缩减,最终计算为一个值。注意:reduce()方法不能对空数组执行回调函数。

1、语法

let arr = []
arr.reduce(callback, [initialValue])

reduce()为数组中的每一个元素依次执行回调函数,其接受两个参数,第一个参数是回调函数,第二个参数是初始值。

callback(previousValue, currentValue, index, arr)
// 其中回调函数接受四个参数:
1、previousValue // reduce()方法提供的初始值(initialValue),或者是上一次调用返回的值
2、currentValue // 数组中的当前元素值
3、index // 当前元素值在数组中的索引
4、arr // 被调用的原数组arr 

2、initialValue参数作用

先看不设置initialValue参数的例子:

let arr = [1, 2, 3, 4]
let sum = arr.reduce(function(prev, cur, index, arr){
    console.log(prev, cur, index);
    return prev + cur
})
console.log(sum, arr);
// 运行结果:
1 2 1
3 3 2
6 4 3
10 [ 1, 2, 3, 4 ]

从上面这个例子可以看出,回调函数的第三个参数:即index,是从1开始的,第一次的prev是数组中的第一个值(1),cur是数组中的第二个值(2);第二次的prev是上次循环返回的二者之和,而cur则变成了数组的第三个值(3),依次类推,但是reduce()函数只循环了三次

当给initialValue参数设置初始值时:

let arr = [1, 2, 3, 4]
let sum = arr.reduce(function(prev, cur, index, arr){
    console.log(prev, cur, index);
    return prev + cur
}, 0)
console.log(sum, arr);
// 运行结果:
0 1 0
1 2 1
3 3 2
6 4 3
10 [ 1, 2, 3, 4 ]

可以看出运行结果是一样的,不同的是这次prev第一次的值是0,cur的值是数组中的第一个值,索引index也是从0开始的,以此类推,reduce()函数循环的次数和数组的长度相同

结论:如果没有提供initialValue参数,则reduce()函数第一次执行时index的值为1跳过了第一个索引(0);如果提供了initialValue参数,则从索引为0的地方开始执行reduce()函数

如果初始数组为空,调用reduce()函数会出现什么问题呢?

let arr = []
let sum = arr.reduce(function(prev, cur, index, arr){
    console.log(prev, cur, index);
    return prev + cur
})
console.log(sum, arr);
//TypeError: Reduce of empty array with no initial value 类型错误:没有初始值的空数组的缩减

但是只要设置了初始值就不会报错:

let arr = []
let sum = arr.reduce(function(prev, cur, index, arr){
    console.log(prev, cur, index);
    return prev + cur
}, 0)
console.log(sum, arr); // 0 []

3、reduce()简单用法

以往求和求积的方法:for、forEach…

// for:
    let arr = [1, 2, 3, 4], sum = 0, pro = 1
    for (var i = 0; i < arr.length; i++) {
        sum += arr[i]
        pro *= arr[i]
    }
// forEach:
	let arr = [1, 2, 3, 4], sum = 0, pro = 1
    arr.forEach( item => {
        sum += item
        pro *= item
    })

而使用reduce()方法可以方便的实现

let arr = [1, 2, 3, 4]
let sum = arr.reduce( function(prev, cur){
    return  prev + cur
})
console.log(sum) // 10
// 使用Es6中的箭头函数可以简写:
let arr = [1, 2, 3, 4]
let sum = arr.reduce( (prev, cur) => prev + cur)
let pro = arr.reduce( (prev, cur) => prev * cur)
console.log(sum) // 10
console.log(pro) // 24

// 也可以在某一数值基础上进行求和求积:
let arr = [1, 2, 3, 4]
let sum = arr.reduce( function(prev, cur){
    return  prev + cur
}, 20)
console.log(sum) // 30
// 简洁写法:
let arr = [1, 2, 3, 4]
let sum = arr.reduce( (prev, cur) => prev + cur, 20)
let pro = arr.reduce( (prev, cur) => prev * cur, 2)
console.log(sum) // 30
console.log(pro) // 48

4、reduce()高级用法

(1)统计数组中每一个元素出现的次数

let pos = ['left', 'right', 'top', 'bottom', 'right']
let posNum = pos.reduce( (prev, cur) => {
    if(cur in prev){
        prev[cur]++
    } else{
        prev[cur] = 1
    }
    return prev
}, {})
console.log(posNum) // { left: 1, right: 2, top: 1, bottom: 1 }

(2)数组去重

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 ]
// includes()方法用来判断一个数组是否包含一个指定的值,如果包含则返回true,否则返回false
// concat()方法用于把参数连接到数组中

(3)计算对象中的属性和

var result = [
    {
        subject: '语文',
        score: 80
    },
    {
        subject: '数学',
        score: 80
    },
    {
        subject: '英语',
        score: 85
    }
]
var sum = result.reduce((prev, cur) => cur.score + prev, 0)
console.log(sum) // 245

数组扁平化

数组扁平化就是将一个多维数组转化为一维数组

(1)最基础的方法就是使用原型的isPrototypeOf()方法,用来检测一个对象是否存在于另一个对象的原型链中,如果存在就返回 true,否则就返回 false

let arr = [1, 2, [3, 4, 5, [6, 7, 8, 9]]]
let newArr = []
function fn(arr){
    arr.forEach( item => {
        Array.prototype.isPrototypeOf(item) ? fn(item) : newArr.push(item)
    })
    return newArr
}
console.log(fn(arr)) 
// 运行结果:
[
  1, 2, 3, 4, 5,
  6, 7, 8, 9
]

(2)也可使用Array.prototype.flat()方法,该方法创建一个新的数组,其中所有子数组元素以递归方式连接到指定的深度

语法: arr.flat(depth)
arr即为需要展平的数组
depth为可选参数,指定嵌套数组结构展平的深度级别,默认为1

let arr = [1, 2, [3, 4, 5, [6, 7, 8, 9]]]

console.log(arr.flat()) // [ 1, 2, 3, 4, 5, [ 6, 7, 8, 9 ] ]
console.log(arr.flat(1)) // [ 1, 2, 3, 4, 5, [ 6, 7, 8, 9 ] ] # 可以看出默认深度为1

console.log(arr.flat(2))
// 结果
[
  1, 2, 3, 4, 5,
  6, 7, 8, 9
]

console.log(arr.flat(4))
// 当参数深度大于数组嵌套的层数,默认也是将数组展平
[
  1, 2, 3, 4, 5,
  6, 7, 8, 9
]

(3)reduce()方法将二维数组转化为一维数组

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

(4)将多维数组转化为一维数组

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

(5)Es6扩展运算符

// 二维数组转化为一维数组:
let arr = [[0, 1], [2, 3], [4, 5]]
let newArr = []
newArr = newArr.concat(...arr)
console.log(newArr) // [ 0, 1, 2, 3, 4, 5 ]

// 多维数组转化为一维数组:
let arr = [[0, 1], [2, 3], [4, [5, 6, 7]], 8, [9]]
let newArr = []
arr.forEach( item => {
    if(Array.isArray(item)){
        newArr = newArr.concat(...item)
    } else{
        newArr.push(item)
    }
    return newArr
})
console.log(newArr)
// 结果
[
  0, 1, 2, 3, 4,
  5, 6, 7, 8, 9
]

(6)toString() & split()

调用toString()方法将数组变为字符串,然后使用split()方法进行分割,此时分割好的是字符串数组,需要通过Number()方法将数组中的每项从string类型变为number类型

let arr = [[0, 1], [2, 3], [4, 5]]
let newArr = []
newArr = arr.toString().split(',').map(item => Number(item))
console.log(newArr) // [ 0, 1, 2, 3, 4, 5 ]

(7)while()循环&some()

let arr = [1, 2, [4, 5, 6 , [7 ,8]], 9]
while(arr.some(Array.isArray)){
    arr = [].concat(...arr)
}
console.log(result)
// 结果
[
  1, 2, 4, 5,
  6, 7, 8, 9
]

这次的分享就到这里了,觉得学到东西的给博主点点关注~~~

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是段段

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值