资讯专栏INFORMATION COLUMN

Javascript 中的map/reduce

zhou_you / 421人阅读

摘要:简单例子一个较为常用的场景就是累加或累乘输出数组元素的乘积输出数组元素的乘积简写形式输出数组元素的乘积形式,营造复杂的逼格用在数组降维扁平化处理的例子中注方法用于连接两个或多个数组。

看到一个提问的回答巧妙地使用了map/reduce操作,很优雅,所以来学习和总结一下javascript自带的map/reduce的使用技巧,文章不会讲的很深,纯当科普一下知识点,如有解释的不正确的地方,欢迎指正。
1.map 1.1 方法概述

map() 方法通过对原数组中的每个元素进行一定的操作(共同调用一个方法),返回一个新的数组。

1.2 简单例子
/**
 * 每个数组元素乘以2输出
 */
var arr1 = [1,2,3,4];
var arr2 = arr1.map(x => {
    return x * 2;
});
console.log(arr2);    // [2,4,6,8]


/**
 * 输出"Hello World"每个字符所对应的 ASCII 码组成的数组:
 */
var a = [].map.call("Hello World", x => {
    return x.charCodeAt(0); 
})
console.log(a);   //[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]

*注:

[ ].map.call() 可以写成 Array.prototype.map.call(); 不懂的可以参看之前的一篇文章:nodejs中call和apply的学习

map函数不改变数组本身:

var arr = [1,2,3,4];
arr.map(x => { return Math.sqrt(x) });
console.log(arr); //[1,2,3,4] 而不是[1, 1.414..., 1.732..., 2]

1.3 语法解释
var new_array = old_array.map(callback, [thisArg]);
其中callback是生成新数组元素的函数,使用三个参数:

currentValue: callback 的第一个参数,数组中正在处理的当前元素。

index: callback 的第二个参数,数组中正在处理的当前元素的索引。

array: callback 的第三个参数,map 方法被调用的数组。

thisArg是可选的。执行 callback 函数时 使用的this 值。
返回值new_array :一个新数组,每个元素都是回调函数的结果。

对于["1", "2", "3"].map(parseInt)语句会输出什么呢?你可能觉的会是[1, 2, 3],但实际的结果是 [1, NaN, NaN],通常使用parseInt时,只需要传递一个参数,但实际上,parseInt可以有两个参数,第二个参数是进制数,可以通过语句"alert(parseInt.length)===2"来验证。map方法在调用callback函数时,会给它传递三个参数:当前正在遍历的元素, 元素索引, 原数组本身。第三个参数parseInt会忽视, 但第二个参数不会,也就是说,parseInt把传过来的索引值当成进制数来使用.从而返回了NaN.

function returnInt(element){
    return parseInt(element,10);
}

["1", "2", "3"].map(returnInt);   // 返回[1,2,3]
2.reduce 2.1 方法概述

reduce() 方法对累加器和数组的每个值 (从左到右)应用一个函数,以将其减少为单个值。内部实现应该是遍历元素,理论上可以通过forEach方法实现其功能。

2.2 简单例子

reduce一个较为常用的场景就是累加或累乘:

/**
 * 输出数组元素的乘积:
 */
var arr = [1,2,3];

var reducer = function add(stepProduct, item) { 
    return stepProduct * item; 
};

var product = arr.reduce(reducer, 1);

console.log(product);     //6


/**
 * 输出数组元素的乘积(简写形式):
 */
var product = [1,2,3].reduce((stepProduct, item) => {
    return stepProduct * item;
},1);
console.log(product);


/**
 * 输出数组元素的乘积(call形式,营造复杂的逼格):
 */
var product = [].reduce.call([1,2,3], (stepProduct, item) => {
    return stepProduct * item;
},1);
console.log(product);

reduce用在数组降维(扁平化处理)的例子中:

var list1 = [[0, 1], [2, 3], [4, 5]];
var list2 = [0, [1, [2, [3, [4, [5, [6]]]]]]];

function flatten(arr){
    return arr.reduce((acc, val) => {
        return acc.concat(Array.isArray(val) ? flatten(val) : val)
    }, []);
};

console.log(flatten(list1));  // [0, 1, 2, 3, 4, 5]
console.log(flatten(list2));  // [0, 1, 2, 3, 4, 5, 6]

*注:

concat() 方法用于连接两个或多个数组。用法参见:JavaScript concat() 方法

flatten用于数组降维。用法参见:JavaScript Array Flatten 与递归使用介绍_javascript技巧

回到文章一开始提及的一道题目,题目是这样的:寻找字符串中出现次数最少的、并且首次出现位置最前的字符。如cbaacfdeaebb,符合要求的是f。其中一个用reduce来解决方案(姑且不评价是否最优方案):

var str = [].reduce.call("cbaacfdeaebb", (p, n) => {
    return p[n] = (p[n] || 0) + 1,p;
},{});   // {c: 2, b: 3, a: 3, f: 1, d: 1, e: 2}

var s = Object.keys(str).reduce(function(p,n){
    return str[p] <= str[n] ? p : n;
});   //1

console.log(s,str[s]); 

/*
 * 以下是上面方法地球人比较容易看懂的改写方式(写完感觉好多余,蜜汁尴尬T_T):
 */
var str = "cbaacfdeaebb".split("").reduce((allItems, item) => {
    allItems[item] = (allItems[item] || 0) + 1;
    return allItems;
},{});   // {c: 2, b: 3, a: 3, f: 1, d: 1, e: 2}

*注:

return p[n] = (p[n] || 0) + 1,p; 是两句代码的简写形式:
p[n] = (p[n] || 0) + 1;
return p;
2.3 语法解释
arr.reduce(callback, [initialValue])
其中callback是执行数组中每个值的函数,包含四个参数

accumulator: 上一次调用回调返回的值,或者是提供的初始值(initialValue)

currentValue: 数组中正在处理的元素

currentIndex: 数据中正在处理的元素索引,如果提供了 initialValue ,从0开始;否则从1开始

array: 调用 reduce 的数组

函数返回函数累计处理的结果。

initialValue为可选项,其值用于第一次调用 callback 的第一个参数。

3 总结

map/reduce是ECMAScript5规范中出现的数组方法,在处理数组的时候巧妙地应用可以达到意想不到的效果,推荐mozilla的技术文档,系统介绍了各种函数的使用方法,其中map/reduce在Array目下。
文中如有错误,欢迎批评指出。(ಡωಡ)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/82032.html

相关文章

  • 翻译连载 | JavaScript轻量级函数式编程-第 8 章:列表操作 |《你不知道的JS》姊妹篇

    摘要:通过对一系列任务建模来理解一些非常重要的函数式编程在列表操作中的价值一些些看起来不像列表的语句作为列表操作,而不是单独执行。映射我们将采用最基础和最简单的操作来开启函数式编程列表操作的探索。函子是采用运算函数有效用操作的值。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson-《You-Dont-Know-JS》作者 关于译者:这是一个流淌着...

    sPeng 评论0 收藏0
  • MongoDB指南---17、MapReduce

    摘要:操作花费的时间,单位是毫秒。处理完成后,会自动将临时集合的名字更改为你指定的集合名,这个重命名的过程是原子性的。作用域在这些函数内部是不变的。上一篇文章指南聚合下一篇文章指南聚合命令 上一篇文章:MongoDB指南---16、聚合下一篇文章:MongoDB指南---18、聚合命令 MapReduce是聚合工具中的明星,它非常强大、非常灵活。有些问题过于复杂,无法使用聚合框架的查询语言...

    jonh_felix 评论0 收藏0
  • MongoDB指南---17、MapReduce

    摘要:操作花费的时间,单位是毫秒。处理完成后,会自动将临时集合的名字更改为你指定的集合名,这个重命名的过程是原子性的。作用域在这些函数内部是不变的。上一篇文章指南聚合下一篇文章指南聚合命令 上一篇文章:MongoDB指南---16、聚合下一篇文章:MongoDB指南---18、聚合命令 MapReduce是聚合工具中的明星,它非常强大、非常灵活。有些问题过于复杂,无法使用聚合框架的查询语言...

    pubdreamcc 评论0 收藏0
  • Hadoop:使用 JavaScript 构建

    摘要:说明本文所有操作均在环境下进行。任何可以使用来编写的应用,最终会由编写。书中分别介绍了如何使用和结合进行开发。工具会创建作业,发送给各个,同时监控整个作业的执行过程。准备好的运行环境之后开始搭建的运行环境,参考单节点集群配置。 说明 本文所有操作均在 linux 环境下进行。 转载请注明出处。 任何可以使用JavaScript来编写的应用,最终会由JavaScript编写。 作为...

    Magicer 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<