阵列缩小法的深度应用
1.reduce方法介绍
reduce()
方法对数组中的每个元素按序执行一个由您提供的 reducer 函数,每一次运行 reducer 会将先前元素的计算结果作为参数传入,最后将其结果汇总为单个返回值
-
一个 “reducer” 函数,包含四个参数:
-
previousValue
:上一次调用callbackFn
时的返回值。在第一次调用时,若指定了初始值initialValue
,其值则为initialValue
,否则为数组索引为 0 的元素array[0]
。 -
currentValue
:数组中正在处理的元素。在第一次调用时,若指定了初始值initialValue
,其值则为数组索引为 0 的元素array[0]
,否则为array[1]
。 -
currentIndex
:数组中正在处理的元素的索引。若指定了初始值initialValue
,则起始索引号为 0,否则从索引 1 起始。 -
array
:用于遍历的数组。
-
-
initialValue
可选作为第一次调用
callback
函数时参数 previousValue 的值。若指定了初始值initialValue
,则currentValue
则将使用数组第一个元素;否则previousValue
将使用数组第一个元素,而currentValue
将使用数组第二个元素。
返回值
使用 “reducer” 回调函数遍历整个数组后的结果
2.使用reduce方法的好处
reduce方法内部使用了迭代器,可以解决一些递归类的问题,日常开发中可以使用它解决非常复杂的嵌套对象,例如:在处理大量嵌套数据(如 JSON 文件)时,javascript 中很少有基本的数组方法会被重复使用,可以单独使用 reduce 以用更少的代码实现相同的结果。
3.reduce方法的实际应用
3.1.记录数组中元素的次数
场景描述:
需要根据数组当中存在的值,去记录每次值出现的次数 arr=[1,2,3,4,5,1,2,3],那么结果就是[{1:2},{2:2},{3;2},{4:1},{5:1}]
解决思路:
判断查找当前元素是不是在数组中已经存在过了,如果不存在,那么它就是第一次出现,记录一下该元素已经存在一次了,如果存在就在之前记录的次数上加一.
function totalNum(arr) {
const newArr = arr.reduce((pre, cur) => {
if (!pre[cur]) {
pre[cur] = 1;
} else {
pre[cur]++;
}
return pre;
}, {});
return newArr;
}
3.2.解决对象数组的去重问题
场景描述:
一般数组去重可以用对象唯一键值的方式,根据object和set的属性名不能重复来判断,但是对象数组就没法判断
解决思路
使用空对象进行存储,从数组中取出对象元素跟目标对象元素进行比对,如果没有,就将当前对象元素push进当前的数组中,否则目标对象中有,则返回空
function unbalance(arr) {
let obj = Object.create(null);
let newArr = arr.reduce((pre, cur) => {
obj[cur.name] ? "" : (obj[cur.name] = 1 && pre.push(cur));
return pre;
}, []);
return newArr;
}
3.3.计算年龄
场景描述
有一个年龄数组,它代表人们出生的年份,我们只想保留18岁以上的人,并计算出人们的年龄
const years = [1997, 1999, 2001,2012,2017,2020];
const currentYear = (new Date).getFullYear();
const reducer = (accumulator, year) => {
const age = currentYear - year;
if (age < 18) {
return accumulator;
}
accumulator.push({
year,
age
});
return accumulator;
}
const over18Ages = years.reduce(reducer, []);
3.4.树的数据处理
需求分析
在封装树组件的时候,经过后端返回数据,我们需要将数据加工成我们所需要的数据,将扁平化的数据做嵌套处理,如果不使用递归,就可以通过reduce实现
需要处理的数据
{"code":0,"parent":[{"name":"文件夹1","pid":0,"id":1},{"name":"文件夹2","pid":0,"id":2},
{"name":"文件夹3","pid":0,"id":3},{"name":"文件夹1-1","pid":1,"id":4},{"name":"文件夹2-
1","pid":2,"id":5}],"child":[{"name":"文件1","pid":1,"id":1001},{"name":"文件
2","pid":1,"id":1002},{"name":"文件2-1","pid":2,"id":1003},{"name":"文件2-
2","pid":2,"id":1004},{"name":"文件1-1","pid":4,"id":1005},{"name":"文件2-1-1","pid":5,"id":1006}]}
处理后的数据
[{"name":"文件夹1","pid":0,"id":1,"children":[{"name":"文件夹1-1","pid":1,"id":4,"children":
[{"name":"文件1-1","pid":4,"id":1005}]},{"name":"文件1","pid":1,"id":1001},{"name":"文件
2","pid":1,"id":1002}]},{"name":"文件夹2","pid":0,"id":2,"children":[{"name":"文件夹2-
1","pid":2,"id":5,"children":[{"name":"文件2-1-1","pid":5,"id":1006}]},{"name":"文件2-
1","pid":2,"id":1003},{"name":"文件2-2","pid":2,"id":1004}]},{"name":"文件夹3","pid":0,"id":3}]
//1.先扁平化数组
const allData = [...data.parent, ...data.child];
//2.做树的映射表,改成以下结构
//{1:{name:"文件夹1",pid:0,id:1}}
const treeData = allData.reduce((pre, cur) => {
pre[cur["id"]] = cur;
return pre;
}, {});
//3.做数据处理
const newData = allData.reduce((pre, cur) => {
//从当前项中拿到pid
let { pid } = cur;
//根据映射表判断是否有对应的对象
let parent = treeData[pid];
if (parent) {
// debugger
// console.log( parent.children,' parent.children');
parent.children
? parent.children.push(cur)
: (parent.children = [cur]);
} else if (pid ===0) {
pre.push(cur);
}
return pre;
}, []);
3.5 使用函数实现管道
需求分析
有一堆函数,需要将上一函数的返回值作为下个函数的入参进行计算,实现一个管道函数
const double = x => x + x;
const triple = x => 3 * x;
const quadruple = x => 4 * x;
const pipe = (...functions) =>initialValue =>functions.reduce((acc, fn) => fn(acc), initialValue);
const multiply6 = pipe(double, triple);
const multiply9 = pipe(triple, triple);
const multiply16 = pipe(quadruple, quadruple);
const multiply24 = pipe(double, triple, quadruple);
multiply6(6); // 36
multiply9(9); // 81
multiply16(16); // 256
multiply24(10); // 240
3.6功能函数集成
需求分析
比如我需要将一个字符串切割成数组,在计算数组的长度,然后根据数组的长度做一系列计算操作
const toWords = (string) => string.split(" ");
const count = (array) => array.length;
const wpm = (wordCount) => wordCount * 30;
const speed = (string, func) =>func.reduce((composed, fn) => fn(composed), string);
speed("wo shi wangsu", [toWords, count, wpm]);
3.7 多个请求的先后执行问题
需求分析
多个请求并发操作,b请求需要在a请求得到相应结果之后操作,除了使用async和await外还可以采用erduce+promise的方式
function runPromiseInSequence(arr, input) {
return arr.reduce(
(promiseChain, currentFunction) => promiseChain.then(currentFunction),
Promise.resolve(input)
);
}
function p1(a) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(a * 5);
}, 1000);
});
}
function p2(a) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(a * 2);
}, 1000);
});
}
function f3(a) {
return a * 3;
}
function p4(a) {
return new Promise((resolve, reject) => {
resolve(a * 4);
});
}
const promiseArr = [p1, p2, f3, p4];
runPromiseInSequence(promiseArr, 10).then(res=>{
console.log(res);
});
3.8使用reduce迭代器解决递归问题
需求分析
递归函数经常被使用,因为它们的语义定义,,如果可以将递归函数转换为迭代方法,就可以使用
reduce
,reduce
如果做得好,在启用声明性定义的同时,就不会有可能填满函数堆栈的问题。
const factorial = (number) =>
number === 0 ? 1 : number * factorial(number - 1);
const factorial = (number) =>
Array(number)
.fill(number)
.reduce((acc, elem, i) => acc * (elem - i));
推荐阅读
-
DeepVO:基于深度递归卷积神经网络的端到端视觉里程测量法
-
35 岁实现财务*,腾讯程序员手握2300万提前退休?-1000万房产、1000万腾讯股票、加上300万的现金,一共2300万的财产。有网友算了一笔账,假设1000万的房产用于自住,剩下1300万资产按照平均税后20-50万不等进行计算,大约花上26-60年左右的时间才能赚到这笔钱。也就是说,普通人可能奋斗一辈子,才能赚到这笔钱。在很多人还在为中年危机而惶惶不可终日的时候,有的人的35岁,就已经安全着陆,试问哪个打工人不羡慕?但问题是有这样财富积累必然有像样的实力做靠山。没有人可以不劳而获。 看到这里,肯定有人说,那么对于普通人来说,卷可能真就成了唯一的出路。但是卷也有轻松的卷,“偷懒”的卷法,对于程序员而言,刨除掉一时无法改掉的开会传统占用的大部分时间,如何把有限的时间和精力放在真正重要的架构设计、需求设计上,而不是重复的造*,编码、改bug、手动测试。因此在科技改变生活的今天,学会使用AI工具成为程序员们的必备技能。 以全栈式全自动的软件开发工具飞算SoFlu软件机器人为例,作为全球首款面向微服务架构设计和最佳实践的软件机器人,SoFlu软件机器人改变了原来手工编码的作业模式,通过可视化拖拽方式以及参数配置就能实现等同于编写复杂代码的业务逻辑,在设计业务逻辑时就完成了微服务应用开发,做到“业务即图,图即代码”,实现“软件开发,十倍提效”。 而作为飞算SoFlu软件机器人的一个重要组成部分,FuncGPT(慧函数)支持所有类型函数创建。通过自然语言描述Java函数需求,实时生成高质量、高可读性的Java函数代码。生成代码可直接复制到IDEA,或一键导入Java全自动开发工具函数库。 FuncGPT(慧函数)具有五大核心能力: ● 自然语言:通过自然语言即可生成函数,降低软件开发门槛。 ● 秒级函数开发:全自动秒级开发函数,秒级完成,效率千倍提升。 ● 一站式函数开发应用:函数生成即可直接应用,效率、安全有保障。 ● 质量可靠:生成的函数代码符合业界规范、具备良好的可读性,符合最优解。 ● 灵活生成:可以根据开发人员的具体需求生成并支持调整和修改。 以“将文件流转换为File对象”这个需求为例,以下是FuncGPT(慧函数)秒级生成的代码: / 类名:FileConverter // 函数名:convertStreamToFile // 函数功能:将文件流转换为File对象 // POM依赖包:无 import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; public class FileConverter { /** * 将文件流转换为File对象 * @param inputStream 文件流 * @param filePath 文件路径 * @param fileName 文件名 * @return 转换后的File对象 * @throws IOException 如果发生I/O异常 */ public static File convertStreamToFile(InputStream inputStream, String filePath, String fileName) throws IOException { File file = new File(filePath + File.separator + fileName); // 创建File对象 try (FileOutputStream outputStream = new FileOutputStream(file)) { // 创建文件输出流 byte buffer = new byte[1024]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { // 从文件流读取数据并写入文件 outputStream.write(buffer, 0, bytesRead); } } return file; // 返回转换后的File对象 } } // 函数示例 // 将文件流转换为File对象示例 // 入参:inputStream,文件流 // 入参:filePath,文件路径 // 入参:fileName,文件名 // 出参:file,转换后的File对象 // 调用示例: // InputStream inputStream = new FileInputStream("example.txt"); // String filePath = "C:\\Users\\User\\Documents"; // String fileName = "example.txt"; // File file = FileConverter.convertStreamToFile(inputStream, filePath, fileName); // System.out.println(file.getAbsolutePath); // 输出结果:例如,将文件流转换为File对象后,文件的绝对路径为:C:\Users\User\Documents\example.txt // 则输出结果为:C:\Users\User\Documents\example.txt 通过分析,不难发现以上代码:
-
深度学习的力量:手写数学表达式识别与前景代码实践与应用
-
openEuler郑州用户组成立!openEuler与hyperfusion携手共建河南地区用户生态 - 开幕致辞 超融合操作系统业务总经理、openEuler委员会成员蒋振华先生为本次活动致辞。 在本次活动的致辞中,他提到,作为openEuler社区早期的成员,超融合见证了openEuler从成立到在各行业商业落地,再到跨越生态拐点的过程,感谢openEuler提供了一个全产业链共同创新的平台,共同推动创新技术的商业落地。 同时,本次活动得到了郑州市郑东新区大数据管理局、郑州中原科技城投资服务局的大力支持。 郑东新区大数据管理局曹光远 在活动致辞中表示,openEuler的应用和*应用设施的深度优化,为郑东新区数字化转型提供了安全、可靠、高性能的技术基础;郑州中原科技城招商服务局王林表示,郑东新区欢迎所有openEuler生态相关企业扎根当地,围绕openEuler社区共同发展,形成合力。 openEuler社区及运维功能介绍 openEuler技术委员会委员胡峰 openEuler技术委员会委员胡峰先生在本次活动中介绍了openEuler社区目前发展的整体情况,并重点从技术层面介绍了openEuler的运维功能。 openEuler 晚会 胡峰先生介绍智能运维工具 A-Ops 和 openEuler gala、 阿波罗 Apollo、智能漏洞管理解决方案等新功能,以及涵盖各种运维场景的精品运维组件。在*交流环节,许多用户就目前使用的 openEuler 在*交流环节,许多用户就自己在使用openEuler过程中遇到的一些问题与胡峰先生进行了进一步的交流。 软硬结合,构建多样化算力操作系统 Hyperfusion 基于 openEuler 的基础上,结合自身软硬件技术积累,推出了富讯服务器操作系统 FusionOS FusionOS. FusionOS 首席架构师张海亮 分享了 FusionOS FusionOS首席架构师张海亮分享了FusionOS的软硬件协同优势、卓越的性能和可靠性,以及FusionOS在金融、运营商、*、互联网等行业的实践案例,引起了众多用户的兴趣,分享结束后,不少参会者就FusionOS的特点向讲师提问并进行了交流。
-
深度学习原理与实践:深度学习在图像分割中的应用
-
吴恩达的深度学习,第四课(4)特殊应用:人脸识别和神经风格迁移
-
深度学习基础知识:介绍深度学习的发展历史、基本概念和主要应用
-
js 数组还原法的使用和一些应用场景
-
阵列缩小法的深度应用
-
阵列还原法是一种详细的解决方案。