JavaScript面试题:Array.prototype.reduce()的使用场景

reduce()方法的使用场景

1、语法

array.reduce((previousValue,currentValue,currentIndex,array)=>{},initialValue)
对数组累计执行回调函数并返回最终结果
在这里插入图片描述
在这里插入图片描述

2、使用场景

2.1 数组元素累计求和

// 不设置初始值initialValue时
let result1 = arr.reduce((previousValue,currentValue,arr) => {
    console.log(previousValue,"previousValue ============");
    console.log(currentValue,"currentValue ============");
    return previousValue + currentValue
})

console.log(result1); // 15

// 设置初始值initialValue时
let initialValue = 0
let result2 = arr.reduce((previousValue,currentValue,arr) => {
    console.log(previousValue,"previousValue ============");
    console.log(currentValue,"currentValue ============");
    return previousValue + currentValue
},initialValue)
console.log(result2); // 15

2.2 二维数组扁平化

let arr = [
    [20,30,20,10,32],
    [21,20,24,19,92],
    [20,43,20,20,32],
    [70,30,29,10,12],
]

let result = arr.reduce((previousValue,currentValue) => {
    return previousValue.concat(currentValue)
},[])

console.log(result);

2.3 统计数组中元素出现的频数

const arr = [
    "a", "b", "a",, "a", "b", "a", "b", "a", "a", "a", "a", "a", "a", "b", "b", "b",
    "c", "c", "c", "c", "a", "b", "a", "b", "a"
]

const result = arr.reduce(
    (previousValue, currentValue) => {
        if(currentValue in previousValue){
            previousValue[currentValue] ++;
        }else{
            previousValue[currentValue] = 1;
        }
        return previousValue;
    }, 
    {}
)

console.log(result)

2.3 对数组中的对象元素分组分类

const arr = [
    { 年级: "2017级", 学院: "计算机学院", 专业: "物联网" },
    { 年级: "2017级", 学院: "计算机学院", 专业: "计算机科学" },
    { 年级: "2018级", 学院: "计算机学院", 专业: "软件工程" },
    { 年级: "2019级", 学院: "计算机学院", 专业: "软件工程" },
    { 年级: "2019级", 学院: "计算机学院", 专业: "物联网" },
    { 年级: "2020级", 学院: "计算机学院", 专业: "物联网" },
    { 年级: "2020级", 学院: "计算机学院", 专业: "计算机科学" },
    { 年级: "2020级", 学院: "计算机学院", 专业: "软件工程" },
    { 年级: "2017级", 学院: "电气学院", 专业: "自动化" },
    { 年级: "2018级", 学院: "电气学院", 专业: "自动化" },
    { 年级: "2019级", 学院: "电气学院", 专业: "自动化" },
    { 年级: "2020级", 学院: "电气学院", 专业: "自动化" },
]


// 根据指定字段的指定值获取分组  
function getByTarget(arr, target, targetValue) {
    // 如果没有指定具体年级,例如: 按照年级分组 
    if (!targetValue) {
        const result = arr.reduce(
            (previousValue, currentValue) => {
                // 拿到当前要分组的条件
                // 例如,currentValue是{ 年级: "2017级", 学院: "计算机学院", 专业: "物联网" }这样一个对象
                // 那么,currentValue[target] 就是年级或者学院或者专业
                let currentTargetValue = currentValue[target]

                // 如果previousValue对象中没有值,则创建一个新数组
                if (!previousValue[currentTargetValue]) {
                    previousValue[currentTargetValue] = []
                }

                // 将符合条件的添加到previousValue[currentTargetValue]数组中
                previousValue[currentTargetValue].push(currentValue)
                return previousValue;
            },
            {}
        )
        return result;
    }

    // 如果还指定了具体年级
    let initObj = {}
    initObj[targetValue] = [];
    const result = arr.reduce(
        (previousValue, currentValue) => {

            // 不是目标值直接跳过
            if (currentValue[target] !== targetValue) {
                return previousValue;
            }

            // 符合要求则加入
            previousValue[targetValue].push(currentValue);

            return previousValue;
        },
        initObj
    )
    return result;
}


result05_01 = getByTarget(arr, "专业")
result05_02 = getByTarget(arr, "学院")
result05_03 = getByTarget(arr, "年级")

// 这里是为了确保函数返回值是一个map而不是数组(统一返回格式) 重在思路
result05_04 = getByTarget(arr, "年级", "2017级")["2017级"]
result05_05 = getByTarget(arr, "学院", "计算机学院")["计算机学院"]
result05_06 = getByTarget(arr, "专业", "自动化")["自动化"]

console.log("按专业分类");
console.log(result05_01)
console.log("按学院分类");
console.log(result05_02)
console.log("按年级分类");
console.log(result05_03)
console.log("取2017级");
console.log(result05_04)
console.log("取计算机学院");
console.log(result05_05)
console.log("取自动化专业");
console.log(result05_06)

结果:

按专业分类
{
‘物联网’: [
{ ‘年级’: ‘2017级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘物联网’ },
{ ‘年级’: ‘2019级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘物联网’ },
{ ‘年级’: ‘2020级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘物联网’ }
],
‘计算机科学’: [
{ ‘年级’: ‘2017级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘计算机科学’ },
{ ‘年级’: ‘2020级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘计算机科学’ }
],
‘软件工程’: [
{ ‘年级’: ‘2018级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘软件工程’ },
{ ‘年级’: ‘2019级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘软件工程’ },
{ ‘年级’: ‘2020级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘软件工程’ }
],
‘自动化’: [
{ ‘年级’: ‘2017级’, ‘学院’: ‘电气学院’, ‘专业’: ‘自动化’ },
{ ‘年级’: ‘2018级’, ‘学院’: ‘电气学院’, ‘专业’: ‘自动化’ },
{ ‘年级’: ‘2019级’, ‘学院’: ‘电气学院’, ‘专业’: ‘自动化’ },
{ ‘年级’: ‘2020级’, ‘学院’: ‘电气学院’, ‘专业’: ‘自动化’ }
]
}
按学院分类
{
‘计算机学院’: [
{ ‘年级’: ‘2017级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘物联网’ },
{ ‘年级’: ‘2017级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘计算机科学’ },
{ ‘年级’: ‘2018级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘软件工程’ },
{ ‘年级’: ‘2019级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘软件工程’ },
{ ‘年级’: ‘2019级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘物联网’ },
{ ‘年级’: ‘2020级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘物联网’ },
{ ‘年级’: ‘2020级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘计算机科学’ },
{ ‘年级’: ‘2020级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘软件工程’ }
],
‘电气学院’: [
{ ‘年级’: ‘2017级’, ‘学院’: ‘电气学院’, ‘专业’: ‘自动化’ },
{ ‘年级’: ‘2018级’, ‘学院’: ‘电气学院’, ‘专业’: ‘自动化’ },
{ ‘年级’: ‘2019级’, ‘学院’: ‘电气学院’, ‘专业’: ‘自动化’ },
{ ‘年级’: ‘2020级’, ‘学院’: ‘电气学院’, ‘专业’: ‘自动化’ }
]
}
按年级分类
{
‘2017级’: [
{ ‘年级’: ‘2017级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘物联网’ },
{ ‘年级’: ‘2017级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘计算机科学’ },
{ ‘年级’: ‘2017级’, ‘学院’: ‘电气学院’, ‘专业’: ‘自动化’ }
],
‘2018级’: [
{ ‘年级’: ‘2018级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘软件工程’ },
{ ‘年级’: ‘2018级’, ‘学院’: ‘电气学院’, ‘专业’: ‘自动化’ }
],
‘2019级’: [
{ ‘年级’: ‘2019级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘软件工程’ },
{ ‘年级’: ‘2019级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘物联网’ },
{ ‘年级’: ‘2019级’, ‘学院’: ‘电气学院’, ‘专业’: ‘自动化’ }
],
‘2020级’: [
{ ‘年级’: ‘2020级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘物联网’ },
{ ‘年级’: ‘2020级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘计算机科学’ },
{ ‘年级’: ‘2020级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘软件工程’ },
{ ‘年级’: ‘2020级’, ‘学院’: ‘电气学院’, ‘专业’: ‘自动化’ }
]
}
取2017级
[
{ ‘年级’: ‘2017级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘物联网’ },
{ ‘年级’: ‘2017级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘计算机科学’ },
{ ‘年级’: ‘2017级’, ‘学院’: ‘电气学院’, ‘专业’: ‘自动化’ }
]
取计算机学院
[
{ ‘年级’: ‘2017级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘物联网’ },
{ ‘年级’: ‘2017级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘计算机科学’ },
{ ‘年级’: ‘2018级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘软件工程’ },
{ ‘年级’: ‘2019级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘软件工程’ },
{ ‘年级’: ‘2019级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘物联网’ },
{ ‘年级’: ‘2020级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘物联网’ },
{ ‘年级’: ‘2020级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘计算机科学’ },
{ ‘年级’: ‘2020级’, ‘学院’: ‘计算机学院’, ‘专业’: ‘软件工程’ }
]
取自动化专业
[
{ ‘年级’: ‘2017级’, ‘学院’: ‘电气学院’, ‘专业’: ‘自动化’ },
{ ‘年级’: ‘2018级’, ‘学院’: ‘电气学院’, ‘专业’: ‘自动化’ },
{ ‘年级’: ‘2019级’, ‘学院’: ‘电气学院’, ‘专业’: ‘自动化’ },
{ ‘年级’: ‘2020级’, ‘学院’: ‘电气学院’, ‘专业’: ‘自动化’ }
]


或者更简单点如下:

const arr = [
    { 年级: "2017级", 学院: "计算机学院", 专业: "物联网" },
    { 年级: "2017级", 学院: "计算机学院", 专业: "计算机科学" },
    { 年级: "2018级", 学院: "计算机学院", 专业: "软件工程" },
    { 年级: "2019级", 学院: "计算机学院", 专业: "软件工程" },
    { 年级: "2019级", 学院: "计算机学院", 专业: "物联网" },
    { 年级: "2020级", 学院: "计算机学院", 专业: "物联网" },
    { 年级: "2020级", 学院: "计算机学院", 专业: "计算机科学" },
    { 年级: "2020级", 学院: "计算机学院", 专业: "软件工程" },
    { 年级: "2017级", 学院: "电气学院", 专业: "自动化" },
    { 年级: "2018级", 学院: "电气学院", 专业: "自动化" },
    { 年级: "2019级", 学院: "电气学院", 专业: "自动化" },
    { 年级: "2020级", 学院: "电气学院", 专业: "自动化" },
]


// 根据指定字段的指定值获取分组  
function getByTarget(arr, target) {
    // 如果没有指定具体年级,例如: 按照年级分组 
        const result = arr.reduce(
            (previousValue, currentValue) => {
                // 拿到当前要分组的条件
                // 例如,currentValue是{ 年级: "2017级", 学院: "计算机学院", 专业: "物联网" }这样一个对象
                // 那么,currentValue[target] 就是年级或者学院或者专业
                let currentTargetValue = currentValue[target]

                // 如果previousValue对象中没有值,则创建一个新数组
                if (!previousValue[currentTargetValue]) {
                    previousValue[currentTargetValue] = []
                }

                // 将符合条件的添加到previousValue[currentTargetValue]数组中
                previousValue[currentTargetValue].push(currentValue)
                return previousValue;
            },
            {}
        )
        return result;
}

// 先进行总体分组
result05_01 = getByTarget(arr, "专业")
result05_02 = getByTarget(arr, "学院")
result05_03 = getByTarget(arr, "年级")

// 再进行具体分组,例如取出物联网专业
console.log(result05_01["物联网"]);

2.4 数组元素去重

let arr = ["a","b","c","d","a","b","e","c","d"]
let result = arr.reduce((previousValue,currentValue) => {
    if(previousValue.indexOf(currentValue) === -1){
        previousValue.push(currentValue)
    }
    return previousValue
},[])

console.log(result);

2.5 模拟实现map函数

Array.prototype.myMap = function(func, callbackThis){
    // 最终返回新的数组
    let res = [];

    // 定义回调函数的执行环境
    // call 第2个参数传入null 则this指向全部对象
    let cbThis = callbackThis || null;

    this.reduce(
        (prev, next, index, arr)=>{
            // 传入map回调函数拥有的参数
            // 把每一项的执行结果push进入res
            res.push(func.call(cbThis, next, index, arr));
            
        }, 
        null);
    
        return res;
}
let arr = [1,2,3,4,5,6,7,8]
let result = arr11.myMap(Math.sqrt)

console.log(result)

3、自定义实现reduce函数

/**
 * @description: 自定义数组的reduce方法
 * @params callback 回调函数
 * @params initialValue 初始值
 * @return 返回处理结果
 */
Array.prototype.myReduce = function (callback, initialValue) {
    if (this == null) {
        throw new TypeError('this is null or undefined');
    }

    if (typeof callback !== 'function') {
        throw new TypeError(`${callback} is not a function`);
    }

    console.log(this); // 传进来的数组对象
    const array = Object(this);
    const len = array.length >>> 0;
    let accumulator = initialValue;

    for (let i = 0; i < len; i++) {
        if (i in array) {
            accumulator = callback.call(undefined, accumulator, array[i], i, array);
        }
    }

    return accumulator;
};

// 使用
let array = [1,2,3,4]

let result = array.myReduce((pre,cur) => {
    pre.push(cur+1)
    return pre
},[])

console.log(result); // [2,3,4,5]

或者循环实现

var reduce = function (nums, fn, init) {
    if (nums.length === 0)
        return init

    nums.forEach((item, index) => {
        init = fn(init, item)
    })

    return init
};

// 被处理的数组
let nums = [1, 2, 3, 4]
// 初始值
let init = 100
// 回调函数
function sum(accum, curr) { return accum + curr * curr; }

console.log(reduce(nums, sum, init));
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值