草庐IT

reduce比你想象中更强大

硅谷干货 2023-03-28 原文

前言

前面的这篇文章 JS 基础! | 扁平数组和JSON树的转换 利用到了 reduce来实现数组转为map,以及结合concat实现数组递归拼接。今天我们来看看还能搞些什么名堂~

简单复习一下 reduce

语法

let value = arr.reduce(function(previousValue, item, index, array) {
  // ...
}, [initial]);

参数:

  • previousValue: 上一个函数调用的结果,第一次等于 initial(如果提供了 initial的话)。
  • item: 当前的数组元素。
  • index:当前索引。
  • arr: 数组本身。

previousValue实际上有点像累加,所以一些地方也会叫将这个参数称为accumulator,存储前面所有的执行结果,最后会成为reduce的结果。


可读性

但通常,你一般是不会完全参照这些参数定义的意思来决定参数名称,而是要看具体开发遇到的场景来给其取可读性高的名称。

部分应用

1. 经典累加器

将数组中的值从左到右累加,大家学reduce的时候第一个例子应该就是这个。这里只是简单的提一下,不是本文的重点~

const a = [1, 2, 8, 7, 4];

const sum = a.reduce((pre, cur) => {
    const res = pre + cur;
    return res;
}, 0);

console.log(sum); // 22

2. 二维数组转一维

结合 concat实现数组扁平化

const arr2 = [
    [1, 2],
    [3, 4],
    [5, 6],
].reduce((acc, cur) => {
    return acc.concat(cur);
}, []);

console.log(arr2); //

3. 多维数组扁平

这个算是上一个的进阶和更为通用的版本~
这篇文章里就用到了类似的,结合 concat 和递归

const arr3 = [
    [1, 2],
    [3, 4],
    [5, [7, [9, 10], 8], 6],
];
const flatten = arr =>
    arr.reduce(
        (pre, cur) => pre.concat(Array.isArray(cur) ? flatten(cur) : cur),
        []
    );
console.log(flatten(arr3)); // [ 1, 2, 3, 4, 5, 7, 9, 10, 8, 6 ]

4. 数组分块

根据传入限制大小,对数组进行分块。
小于限制长度时就往里添加,否则直接将其加入res

const chunk = (arr, size) => {
    return arr.reduce(
        (res, cur) => (
            res[res.length - 1].length < size
                ? res[res.length - 1].push(cur)
                : res.push([cur]),
            res
        ),
        [[]]
    );
};
const arr4 = [1, 2, 3, 4, 5, 6];
console.log(chunk(arr4, 3)); // [ [ 1, 2, 3 ], [ 4, 5, 6 ] ]

5. 字符统计

统计文本中各个字的数量

const countChar = text => {
    text = text.split("");
    return text.reduce((record, c) => {
        record[c] = (record[c] || 0) + 1;
        return record;
    }, {});
};
const text = "划水水摸鱼鱼";
console.log(countChar(text)); // { '划': 1, '水': 2, '摸': 1, '鱼': 2 }

思考

本文只讲了几个应用,其实还有更多的应用,以及一些实现 JS API 的功能,比如

  • 数组填充
  • 求最大、最小值
  • reverse
  • map
  • ...

等等,这些代码段的整合网上已经有够多了,我这里想总结一下写出这些实用、通用的代码需要进行怎样的思考

core-js

其实从 Polyfill ofArray.prototype.reduceincore-js 中可以从另一个角度理解 reduce 中第一个参数回调函数中接收的第一个参数:

class Array {
  //...
  reduce(callbackfn: (memo: any, value: any, index: number, target: any) => any, initialValue?: any): any;
 //...
}

他这里用的是 memo,中文直接翻译过来就是备忘录,在计算机中我们或许更为喜欢用缓存。我个人认为是更为符合我们写出好用的代码片段的。
他的精髓所在正是将回调函数作用于数组中的各个成员上,而上一次return的值就作为memo,传入到下一个之中,你可以在这里面逐一处理:

  • 不断更新迭代(累加)
  • 将结果拼接(扁平化)
  • 将特定的值添加到同一个对象之中(字符统计)

最后作为想要得到最终效果展现出来~

总结

image.png

写代码,大概是这么几个节点

  1. 了解语法
    1. 传参
    2. 返回
  2. 真正领悟到语言的特性,并能将其运用到实际开发中,写出更好更简洁更实用的代码
  3. 多看:要从从这些代码段中以及网上各路好汉写的实用代码学习怎么样真正地像写诗一样写代码~
  4. 多写

有关reduce比你想象中更强大的更多相关文章

  1. ruby-on-rails - 在 Rails 中更高效地查找或创建多条记录 - 2

    我有一个应用需要发送用户事件邀请。当用户邀请friend(用户)参加事件时,如果尚不存在将用户连接到该事件的新记录,则会创建该记录。我的模型由用户、事件和events_user组成。classEventdefinvite(user_id,*args)user_id.eachdo|u|e=EventsUser.find_or_create_by_event_id_and_user_id(self.id,u)e.save!endendend用法Event.first.invite([1,2,3])我不认为以上是完成我的任务的最有效方法。我设想了一种方法,例如Model.find_or_cr

  2. ruby - 用 map reduce 解决一个问题 - 2

    我想在ruby​​中模拟我对像hadoop这样的系统的map和reduce函数的实现,以验证这个想法至少有效。我有以下问题。我有两个元素列表:List13-A4-B5-C7-D8-FList22-A8-B6-C9-D4-E我需要构建一个公共(public)列表,其中包括与两个列表中公共(public)字母关联的数字总和:commonList5-A12-B11-C16-D我想用map和reduce操作制作一个ruby​​脚本来解决这个问题。我不确定如何解决这个问题或在ruby​​脚本中模拟这个问题要遵循什么程序。感谢任何帮助。 最佳答案

  3. ruby - 在 Ruby 中编写 C 接口(interface)比在 Perl 中更容易吗? - 2

    根据officialrubyAboutpage用C扩展Ruby比用Perl更容易。我不是(perl)XS专家,但我发现使用Inline::C快速简单地编写一些东西非常简单,那么为什么在Ruby中更容易呢?WritingCextensionsinRubyiseasierthaninPerlorPython,withaveryelegantAPIforcallingRubyfromC.ThisincludescallsforembeddingRubyinsoftware,foruseasascriptinglanguage.ASWIGinterfaceisalsoavailable.那些做

  4. ruby - 在 Ruby 中更优雅的方式来做到这一点 - 2

    我从Ruby开始,每天都在寻找新的、更短、更优雅的方式来编写代码。在解决ProjectEuler问题时,我写了很多类似的代码ifbest_score有没有更优雅的写法? 最佳答案 best_score=[best_score,current_score].max参见:可枚举。max免责声明:虽然这更具可读性(恕我直言),但性能较差:require'benchmark'best_score,current_score,n=1000,2000,100_000Benchmark.bmdo|x|x.report{n.timesdobest_

  5. ruby - Ruby 1.9 正则表达式是否与上下文无关语法同样强大? - 2

    我有这个正则表达式:regex=%r{\A(?a\ga|b\gb|c)\Z}x当我针对多个字符串测试它时,它似乎与上下文无关语法一样强大,因为它正确地处理了递归。regex.match("aaacaaa")#=>#regex.match("aacaa")#=>#regex.match("aabcbaa")#=>#regex.match("aaacaa")#=>nil"FunwithRuby1.9RegularExpressions"有一个例子,他实际上安排了一个正则表达式的所有部分,使其看起来像一个上下文无关的语法,如下所示:sentence=%r{(?cat|dog|gerbil){

  6. ruby-on-rails - 在 Rails 中更改错误字段名称 - 2

    我想知道是否有办法更改与之关联的验证错误的字段名称。例如,如果我在没有任何数据的情况下提交FirstName(实际上是表中的fname),它会大喊Fnamecan'tbeblank.是否可以将其更改为FirstNamecan'tbeblank? 最佳答案 现在的一般做法是编辑您的locals像这样:#config/locales/en.ymlen:activerecord:attributes:user:fname:"FirstName"您的错误消息现在将显示“FirstNamecan'tbe...”为了完整起见,您还有另一种选择。

  7. ruby-on-rails - 设计和强大的参数 - 2

    我想知道如何整合这两个gem(设计+强参数),因为强参数可能会在4.0中添加到rails核心欢迎任何帮助谢谢 最佳答案 devise4.x更新classApplicationController添加两个gem后,devise将正常工作。更新:使用最新版本的Devise3.x,如devise#strong-parameters所述、身份验证key(通常是电子邮件字段)和密码字段已被允许。但是,如果注册表单上有任何其他字段,您需要让Devise知道允许的额外字段。最简单的方法是使用过滤器:classApplicationControll

  8. 推出 JetBrains Aqua:为测试自动化打造的强大 IDE初步了解 - 2

    目录啥是Aqua? 视频介绍初体验​小伙伴可能遇到问题总结:啥是Aqua?        JetBrainsAqua是一款可以感知上下文的智能IDE,能够理解Java、Kotlin、Python、JavaScript、TypeScript和SQL等语言,并为每种语言提供智能编码辅助。详情链接JetBrainsAqua官网速达-下载         在Aqua中,我们融合了测试自动化工程师在日常工作中需要的一切,包括多语言IDE(支持JVM、Python和JavaScript等)、HTTP客户端、数据库管理功能、Docker支持、TMS客户端,以及一款用于UI自动化的新型强大Web检查器。 视频

  9. Selenium怎么上传文件,比你想的方式还多 - 2

    在软件测试行业呆了几年,收集了很多【教程】和【面试题】,现在分享给有需要的人,评论区回复或者直接私我:jiubing1Selenium封装了现成的文件上传操作。但是随着现代前端框架的发展,文件上传的方式越来越多样。而有一些文件上传的控件,要做自动化控制会更复杂一些,这篇文章主要讨论在复杂情况下,如何通过自动化完成文件上传。1.input元素上传文件如果页面需要文件上传,那么在大多数情况下,都能在页面源代码中找到一个input的元素。如果能直接在页面当中看到这个input元素,那么通过selenium的send_keys方法就能完成文件的上传,在参数中传入本地文件的路径。driver.get('

  10. ruby - inject 和 ruby​​ 中的 reduce 是一样的吗? - 2

    我看到他们一起记录了here.它们是一样的吗?为什么Ruby有那么多别名(比如数组的map/collect)?非常感谢。 最佳答案 是的,它在许多其他编程语言和数学中也被称为fold。为了让具有不同背景的程序员更直观,Ruby有很多别名。如果您想在数组上使用#length,您可以。如果你想使用#size,那也没关系! 关于ruby-inject和ruby​​中的reduce是一样的吗?,我们在StackOverflow上找到一个类似的问题: https://s

随机推荐