【JS】详解reduce()方法及其奇技淫巧、性能

news2025/1/16 1:05:01

历史小剧场

或许到人生的最后一刻,他都不知道自己为什么会死,他永远也不会知道,在这个世界上,有着许多或明或暗的规则,必须适应,必须放弃原则,背离良知,与光同尘,否则你有多么伟大的抱负、多么光辉的理想,都终将被湮灭。
袁崇焕是不知道与光同尘的,由始至终,他都是一个不上道的人,他有才能、有抱负、有个性,施展自己的才能,实现自己的抱负,彰显自己的个性,如此而已。----《明朝那些事儿》

概念及参数

  • 定义:对数组中的每个元素执行一个自定义的累加器,
  • 参数:第一个:回调函数;第二个:初始值(可选)
  • 回调函数参数(4个):
    • acc: 累计器完成计算的返回值(必选)
    • val: 当前迭代到的元素(必选)
    • index: 当前迭代到的元素在数组中的位置索引(可选)
    • arr: 原数组对象

奇技淫巧

1. 累加累乘
const accumulation = (...vals) => vals.reduce((acc, val) => acc + val, 0);
const multiplication = (...vals) => vals.reduce((acc, val) => acc * val, 1);

console.log(accumulation(1, 2, 3, 4, 5)); // 15
console.log(multiplication(1, 2, 3, 4, 5)); // 120
2. 权重求和
const scores = [
    { score: 90, subject: "chinese", weight: 0.5 },
    { score: 95, subject: "math", weight: 0.3 },
    { score: 85, subject: "english", weight: 0.2 }
]
const result = scores.reduce((acc, val) => acc + val.score * val.weight, 0);
console.log(result); // 90.5
3. 代替reverse()
const reverse = (arr = []) => arr.reduce((acc, val) => [val].concat(acc), []);
console.log(reverse([1, 2, 3, 4, 5])); // [5, 4, 3, 2, 1]
4. 代替map()和filter()
const arr = [0, 1, 2, 3];

console.log(arr.map(val => val * 2)) // [ 0, 2, 4, 6 ]
console.log(arr.reduce((acc, val) => [...acc, val * 2], [])) // [ 0, 2, 4, 6 ]

console.log(arr.filter(val => val > 1)) // [ 2, 3 ]
console.log(arr.reduce((acc, val) => acc.concat(val > 1 ? val : []), [])) // [ 2, 3 ]

console.log(arr.filter(val => val > 1).map(val => val * 2)) // [ 4, 6 ]
console.log(arr.reduce((acc, val) => acc.concat(val > 1 ? val * 2 : []), [])) // [ 4, 6 ]
5. 代替some和every
const scoreList = [
    { subject: 'chinese', score: 45 },
    { subject: 'Math', score: 90 },
    { subject: 'English', score: 60 }
]
// 代替some
console.log(scoreList.reduce((acc, val) => acc || val.score >= 60, false)) // true
// 代替every
console.log(scoreList.reduce((acc, val) => acc && val.score >= 60, false)) // false
6. 数组分割
const chunk = (arr = [], size = 1) => arr.length ?
    arr.reduce((acc, val) => (
        Object.is(acc[acc.length - 1].length, size) ?
        acc.push([val]) : acc[acc.length - 1].push(val), acc
    ), [[]])
    : []

console.log(chunk([1, 2, 3, 4, 5], 1))  // [ [ 1 ], [ 2 ], [ 3 ], [ 4 ], [ 5 ] ]
console.log(chunk([1, 2, 3, 4, 5], 2))  // [ [ 1, 2 ], [ 3, 4 ], [ 5 ] ]
console.log(chunk([1, 2, 3, 4, 5], 3))  // [ [ 1, 2, 3 ], [ 4, 5 ] ]
console.log(chunk([1, 2, 3, 4, 5], 4))  // [ [ 1, 2, 3, 4 ], [ 5 ] ]
console.log(chunk([1, 2, 3, 4, 5], 5))  // [ [ 1, 2, 3, 4, 5 ] ]
console.log(chunk([1, 2, 3, 4, 5], 6))  // [ [ 1, 2, 3, 4, 5 ] ]
7. 数组过滤
const difference = (arr = [], oarr = []) => arr.reduce((acc, val) => (!oarr.includes(val) && acc.push(val), acc), [])
console.log(difference([1, 2, 3, 4, 5], [2, 3, 6]))  // [ 1, 4, 5 ]
8. 数组填充
const fill = (arr = [], data = '', start = 0, count = 0) => {
    const end = arr.length - 1;
    if (start < 0 || start > end) return arr;
    return [
        ...arr.slice(0, start),
        ...arr.slice(start, start + count).reduce((acc, val) => (acc.push(data || val), acc), []),
        ...arr.slice(start, end + count)
    ]
}
const fillArr = [0, 1, 2, 3, 4, 5, 6];
console.log(fill(fillArr, 'aaa', 2, 3)) // [0,1,'aaa','aaa', 'aaa',2,3,4,5,6]
9. 数组扁平
console.log("------------------------------")
const flat = (arr = []) => arr.reduce((acc, val) => {
    return acc.concat(Array.isArray(val) ? flat(val) : val)
}, [])
const flatArr = [0, 1, [2, 3], [4, 5, [6, 7]], [8, [9, 10, [11, 12]]]];
console.log(flat(flatArr)) 
10. 数组去重
const unique = (arr = []) => arr.reduce((acc, val) => !acc.includes(val) ? [...acc, val] : acc , [])
console.log(unique([2, 1, 0, 3, 2, 1, 2])) // [ 2, 1, 0, 3 ]
11. 数组最大最小值
const max = (arr = []) => arr.reduce((acc, val) => Math.max(acc, val))
console.log(max([12, 45, 21, 65, 38, 76, 108, 43])) // 108
const min = (arr = []) => arr.reduce((acc, val) => Math.min(acc, val))
console.log(min([12, 45, 21, 65, 38, 76, 108, 43])) // 12
12. 数组成员独立拆解
const unzip = (arr = []) => arr.reduce(
    (acc, val) => (val.forEach((subVal, index) => acc[index].push(subVal)), acc),
    Array.from({ length: Math.max(...arr.map(val => val.length)) }).map(() => [])
)
const zipArr = [["a", 1, true], ["b", 2, false]];
console.log(unzip(zipArr)) // [ [ 'a', 'b' ], [ 1, 2 ], [ true, false ] ]
13. 数组成员个数统计
const count = (arr = []) => arr.reduce((acc, val) => (acc[val] = (acc[val] || 0) + 1, acc), {})
console.log(count([1, 2, 3, 2, 1, 2])) // { '1': 2, '2': 3, '3': 1 }
14. 数组成员位置记录
const position = (arr = [], target) => arr.reduce((acc, val, i) => (Object.is(val, target) && acc.push(i), acc), [])
console.log(position([2, 1, 3, 2, 1, 2], 2)) // [ 0, 3, 5 ]
15. 数组成员特性分组
const group = (arr = [], key) => key ?
    arr.reduce((acc, val) => (!acc[val[key]] && (acc[val[key]] = []), acc[val[key]].push(val), acc), {})
    : {}
const groupArr = [
    { area: "GZ", name: "YZW", age: 22 },
    { area: "GZ", name: "TYJ", age: 20 },
    { area: "SZ", name: "AAA", age: 22 },
    { area: "FS", name: "BBB", age: 23 },
    { area: "SZ", name: "CCC", age: 20 }
]; 
console.log(group(groupArr, "area")) 
// {
// GZ: [
//     { area: 'GZ', name: 'YZW', age: 22 },
//     { area: 'GZ', name: 'TYJ', age: 20 }
// ],
// SZ: [
//     { area: 'SZ', name: 'AAA', age: 22 },
//     { area: 'SZ', name: 'CCC', age: 20 }
// ],
// FS: [ { area: 'FS', name: 'BBB', age: 23 } ]
// }
console.log("------------------------------")
console.log(group(groupArr, "age"))
16. 字符串反转
const reverseStr = (str = '') => str.split('').reduceRight((acc, val) => acc + val)
console.log(reverseStr('reduce真强')) // 强真ecuder
17. 斐波那契数列
const fibonacci = (len = 0) => {
    const arr = [...Array(len).keys()]
    return arr.reduce((acc, val, index) => (index > 1 && acc.push(acc[index - 1] + acc[index - 2]), acc), [0, 1])
}

console.log(fibonacci(10)) // [0, 1,  1,  2,  3, 5, 8, 13, 21, 34]
18. URL参数反序列化
const parseUrlParam = (url = '') => {
    const params = url.split('?')[1]
    return params ? params.split('&').reduce((acc, val) => {
        const [key, value] = val.split('=')
        acc[key] = decodeURIComponent(value)
        return acc
    }, {}) : {}
}
console.log(parseUrlParam('https://www.baidu.com/s?wd=reduce&ie=utf-8')) // { wd: 'reduce', ie: 'utf-8' }
19. URL参数序列化
const stringifyUrlParam = (obj = {}) => Object.entries(obj).reduce((acc, val) => {
    const [key, value] = val
    return `${acc}${key}=${encodeURIComponent(value)}&`
}, obj.length === 0 ?  "" : "?").slice(0, -1)
console.log(stringifyUrlParam({ wd: 'reduce', ie: 'utf-8' })) // 'wd=reduce&ie=utf-8'
20. 返回对象指定键值
const getKeys = (obj = {}, keys = []) => keys.reduce((acc, val) => (acc[val] = obj[val], acc), {})
console.log(getKeys({ a: 1, b: 2, c: 3 }, ['a', 'c'])) // { a: 1, c: 3 }
21. 数组转对象
const people = [
    { area: "GZ", name: "YZW", age: 27 },
    { area: "SZ", name: "TYJ", age: 25 }
];
const peopleObj = people.reduce((acc, val, index, arr) => {
    const { name, ...rest } = val
    acc[name] = rest
    return acc
}, {})
console.log(peopleObj) // { YZW: { area: 'GZ', name: 'YZW', age: 27 }, TYJ: { area: 'SZ', name: 'TYJ', age: 25 } }
22. 功能性函数管道(函数组合)
const double = val => val * 2;
const add = val => val + 1;
const pipe = (...funcs) => val => funcs.reduce((acc, func) => func(acc), val);

// ===
// const pipe = (...funcs) => {
//     return (val) => {
//         return reduce(funcs, (acc, func) => func(acc), val);
//     }
// }

console.log(pipe(double, add)(5)); // 5 * 2 + 1 = 11

性能测试

1. 数据量较小:1000条
const list = [...Array(1000).keys()];

// map
console.time("map")
let sum3 = 0;
list.map(val => (sum3 += val, val))
console.log(sum3);
console.timeEnd("map")


// for
console.time('for');
let sum1 = 0;
for (let i = 0, len = list.length; i < len; i++) {
    sum1 += list[i];
}
console.log(sum1);
console.timeEnd('for');

// forEach
console.time('forEach');
let sum2 = 0;
list.forEach(val => {
    sum2 += val;
});
console.log(sum2);
console.timeEnd('forEach');

// reduce
console.time("reduce")
let sum4 = list.reduce((acc, val) => (acc += val, acc), 0)
console.log(sum4);
console.timeEnd("reduce")

运行结果

在这里插入图片描述
在数据量较小的情况下,reduce()方法性能较好;for循环方法性能较差(注意:在不同机器上会有差异)

2. 数据量较大:10000000

在这里插入图片描述
在数据量较小的情况下,for循环方法性能较好;map()方法性能较差(注意:在不同机器上会有差异)

注意:这里的for循环获取数组长度只获取了一次

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1791099.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PCL 抛物线回归拟合(Quadratic,二维)

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 这里仍然是最小二乘法的应用,其推导过程如下所述: 1.二次函数模型: 其中,a、b 和 c 是需要确定的参数。 2.最小二乘法 假设我们有一组数据点 ( x 1 ​ , y

python中的函数概念

一段可以被重复使用的代码。 关于函数的定义 defdefine &#xff08;定义&#xff09; def 函数名&#xff08;形参列表&#xff09;&#xff1a;形参列表中&#xff0c;可以有多个形参&#xff0c;多个形参之间使用逗号分隔&#xff0c; 关于函数的调用 &#xff08;开始完…

[240605] FreeBSD 发布 v14.1 | ChatGPT 出现故障,部分用户无法使用

目录 FreeBSD 发布 v14.1ChatGPT 出现故障&#xff0c;部分用户无法使用 FreeBSD 发布 v14.1 一、概述 FreeBSD 项目发布了 FreeBSD 14.1-RELEASE&#xff0c;这是 stable/14 分支的第二个稳定版本。 二、主要更新 C 库在 amd64 架构上实现了 SIMD 字符串和内存操作&#x…

业财一体化的重点、难点和模式

业财一体化的内涵是企业将经营活动、财务管理、经营决策等进行科学的融合和管理&#xff0c;进而提高企业经营管理和财务决策的科学性&#xff0c;同时&#xff0c;基于IT技术、流程再造和组织重构更好的保障企业价值创造功能的实现。其涵盖管理循环、业务循环、信息循环三个双…

Bowyer-Watson算法

数学原理及算法过程 Delaunay 三角剖分是一种特殊的三角剖分方法&#xff0c;它满足以下两个重要性质&#xff1a; 最大化最小角性质&#xff1a;Delaunay 三角剖分通过避免细长的三角形来最大化所有三角形的最小角。空外接圆性质&#xff1a;在 Delaunay 三角剖分中&#xf…

lib库和dll库的介绍和使用

lib&#xff08;静态库&#xff09; 静态库定义&#xff1a;.lib文件是静态库文件&#xff0c;包含了在编译时被链接到目标程序的代码。使用静态库时&#xff0c;库的代码会被复制到最终生成的可执行文件中。优点&#xff1a; 性能&#xff1a;由于库代码在编译时就被集成到可…

大创报名步骤

目录 一、注册 二、创建项目 三、报名 一、注册 进入注册/登录 点击 点击 填写个人信息 二、创建项目 找到解压的文件 随便选一个 项目简介在你选择的文件中截取一段 询问自己寝室的人 被邀请者需要在微信公众号上搜索 “全国大学生创业服务网” 选择我的消息中同意 三、报名…

springcloud第4季 springcloud-gateway网关filter案例场景

一 filter作用 1.1 filter搭建流程 1.1.1 网关配置 1.1.2 服务提供者 1.1.3 测试验证 1.启动consul 2.启动zipkin 3.启动应用微服务 4.进行访问&#xff1a; http://localhost:6666/pay/wg/filter 1.2 其他常见API RemoveRequestHeadersec-fetch-site # 删除请求…

身份证数字识别DBNET

采用DBNET检测身份证数字所在区域&#xff0c;然后使用切割字符的方法&#xff0c;使用PCASVM训练和分类&#xff0c;支持C/PYTHON开发&#xff0c;只需要OPENCV 身份证数字识别DBNETPCASVM

网关(Gateway)- 内置过滤器工厂

官方文档&#xff1a;Spring Cloud Gateway 内置过滤器工厂 AddRequestHeaderGatewayFilterFactory 为请求添加Header Header的名称及值 配置说明 server:port: 8088 spring:application:name: api-gatewaycloud:nacos:discovery:server-addr: 127.0.0.1:8847username: nacos…

栈排序00

题目链接 栈排序 题目描述 注意点 对栈进行排序使最小元素位于栈顶最多只能使用一个其他的临时栈存放数据不得将元素复制到别的数据结构&#xff08;如数组&#xff09;中栈中的元素数目在[0, 5000]范围内 解答思路 本题是要实现一个小顶堆&#xff0c;可以直接使用Priori…

Autonomous Mobile 3D Printing of Large-Scale Trajectories——文献精读

一、文章信息 标题&#xff1a;Autonomous Mobile 3D Printing of Large-Scale Trajectories 作者&#xff1a;Julius Sustarevas 发表刊物&#xff1a;IEEE/RSJ 智能机器人与系统国际会议 &#xff08;IROS&#xff09; 发表时间&#xff1a;2022年10月23-27日 二、背景 大…

AI短片制作全流程详解——掌握未来视频创作新技能!

老铁们! 期待已久的AI短片免费直播分享来了&#xff01;&#xff01;&#xff01; 还是老规矩&#xff0c;只讲干货&#xff0c;全程不废话! 在这个直播中&#xff0c;我们将深入探讨AI短片制作的全过程&#xff0c;从构思到最终输出&#xff0c;全方位解析每一个步骤的关键要素…

Ant Design Vue Table组件全单元格编辑实现方案

在ant上的table常见用法是一行的元素可编辑&#xff0c;如下&#xff1a; 但是现在有一个需求是全部单元格均可编辑&#xff0c;如何实现呢&#xff1f; 表格组件 <a-tablev-if"query.personnel_type 0"size"middle"row-key"id":scroll&qu…

中继器、集线器、网桥、交换机、路由器和网关

目录 前言一、中继器、集线器1.1 中继器1.2 集线器 二、网桥、交换机2.1 网桥2.1.1 认识网桥2.1.2 网桥的工作原理2.1.3 生成树网桥 2.2 交换机2.2.1 交换机的特征2.2.2 交换机的交换模式2.2.3 交换机的功能 三、路由器、网关3.1 路由器的介绍3.2 路由器的工作过程3.2.1 前置知…

迅雷极简易下载

一、简介 1、迅雷是一家全球领先的去中心化服务商&#xff0c;以技术构建商业&#xff0c;以服务创造共识&#xff0c;从而建立一个高效可信的存储与传输网络。 迅雷成立于2003年&#xff0c;总部位于中国深圳&#xff0c;2014年于纳斯达克上市&#xff08;纳斯达克股票代码&a…

Threejs墙体挖洞做门或窗

在使用Threejs代码构建的展厅中&#xff0c;需要在一面墙中间挖个洞作为门或窗户&#xff0c;效果如下&#xff1a; 引入ThreeBSP.js <script src"plugins/three/ThreeBSP.js"></script> 创建 // 1 定义墙面var cubeGeometry new THREE.BoxGeometry(1…

4.2 索引及其操作

对数据库中的表进行查询操作时有两种搜索扫描方式&#xff0c;一种是全表扫描&#xff0c;另一种就是使用表上建立的索引进行扫描。 全表扫描要查找某个特定的行&#xff0c;必须从头开始一一查看表中的每一行&#xff0c;与查询条件做对比&#xff0c;返回满足条件的记录&…

FFA-Net:用于单图像去雾的特征融合注意力网络

摘要 论文链接&#xff1a;https://arxiv.org/pdf/1911.07559v2 在这篇论文中&#xff0c;我们提出了一种端到端的特征融合注意力网络&#xff08;FFA-Net&#xff09;来直接恢复无雾图像。FFA-Net架构由三个关键组件组成&#xff1a; 一种新颖的特征注意力&#xff08;FA&…

Mac下删除系统自带输入法ABC,正解!

一、背景说明 MacOS 在 14.2 以下的系统存在中文输入法 BUG&#xff0c;会造成系统卡顿&#xff0c;出现彩虹圆圈。如果为了解决这个问题&#xff0c;有两种方法&#xff1a; 升级到最新的 14.5 系统使用第三方输入法 在使用第三方输入法的时候&#xff0c;会发现系统自带的 …