Array高阶函数reduce&filter

① reduce()方法

一、语法

arr.reduce(callback,[initialValue])
复制代码

reduce 为数组中的每个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素,接受四个参数:初始值(或者上一次回调函数的返回值),当前元素值,当前索引,调用 reduce 的数组。git

callback (执行数组中每一个值的函数,包含四个参数)

    1、previousValue (上一次调用回调返回的值(没有提供initialValue),或者是提供的初始值(initialValue))
    2、currentValue (数组中当前被处理的元素)
    3、index (当前元素在数组中的索引)
    4、array (调用 reduce 的数组)

initialValue (做为第一次调用 callback 的第一个参数。)
复制代码

二、实例解析 initialValue 参数

  1. 没有提供initialValue参数github

    var arr = [1, 2, 3, 4];
    var sum = arr.reduce(function(prev, cur, index, arr) {
        console.log(prev, cur, index);
        return prev + cur;
    })
    console.log(arr, sum);
    // 打印结果: 
    // 1 2 1
    // 3 3 2
    // 6 4 3 
    // [1, 2, 3, 4, 5] 15
    复制代码

    这里能够看出,上面的例子index是从1开始的,第一次的prev的值是数组的第一个值。数组长度是4,可是reduce函数循环3次。数组

  2. 提供initialValue参数安全

    var  arr = [1, 2, 3, 4];
    var sum = arr.reduce(function(prev, cur, index, arr) {
        console.log(prev, cur, index);
        return prev + cur;
    },0) //注意这里设置了初始值
    console.log(arr, sum);
    
     // 打印结果: 
     // 0 1 0
     // 1 2 1
     // 3 3 2 
     // 6 4 3
     // [1, 2, 3, 4] 10
    复制代码

    这个例子index是从0开始的,第一次的prev的值是咱们设置的初始值0,数组长度是4,reduce函数循环4次。app

结论:若是没有提供initialValue,reduce 会从索引1的地方开始执行 callback 方法,跳过第一个索引。若是提供initialValue,从索引0开始。函数

注意:若是这个数组为空,运用reduce是什么状况?测试

var  arr = [];
var sum = arr.reduce(function(prev, cur, index, arr) {
    console.log(prev, cur, index);
    return prev + cur;
})
//报错,"TypeError: Reduce of empty array with no initial value"
复制代码

可是要是咱们设置了初始值就不会报错,以下:ui

var  arr = [];
var sum = arr.reduce(function(prev, cur, index, arr) {
    console.log(prev, cur, index);
    return prev + cur;
},0)
console.log(arr, sum); // [] 0
复制代码

因此通常来讲咱们提供初始值一般更安全this

三、reduce的高级用法

  1. 计算数组中每一个元素出现的次数spa

    let names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];
    
    let nameNum = names.reduce((pre,cur)=>{
      if(cur in pre){
        pre[cur]++
      }else{
        pre[cur] = 1 
      }
      return pre
    },{})
    console.log(nameNum); //{Alice: 2, Bob: 1, Tiff: 1, Bruce: 1}
    复制代码
  2. 数组去重

    let arr = [1,2,3,4,4,1]
    let newArr = arr.reduce((pre,cur)=>{
        if(!pre.includes(cur)){
          return pre.concat(cur)
        }else{
          return pre
        }
    },[])
    console.log(newArr);// [1, 2, 3, 4]
    //-----------------------------------------------
    let arr = [1,2,1,2,3,5,4,5,3,4,4,4,4];
    let result = arr.sort().reduce((init, current)=>{
        if(init.length===0 || init[init.length-1]!==current){
            init.push(current);
        }
        return init;
    }, []);
    console.log(result); //[1,2,3,4,5]
    
    // 不能使用 pre.push(cur) 由于数组的push方法返回的是新数组的长度,而concat返回的是新数组
    复制代码
  3. 将二维数组转化为一维

    let arr = [[0, 1], [2, 3], [4, 5]]
    let newArr = arr.reduce((pre,cur)=>{
        return pre.concat(cur)
    },[])
    console.log(newArr); // [0, 1, 2, 3, 4, 5]
    复制代码
  4. 将多维数组转化为一维

    let arr = [[0, 1], [2, 3], [4,[5,6,7]]]
    const newArr = function(arr){
       return arr.reduce((pre,cur)=>pre.concat(Array.isArray(cur)?newArr(cur):cur),[])
    }
    console.log(newArr(arr)); //[0, 1, 2, 3, 4, 5, 6, 7]
    复制代码
  5. 对象里的属性求和

    var result = [
        {
            subject: 'math',
            score: 10
        },
        {
            subject: 'chinese',
            score: 20
        },
        {
            subject: 'english',
            score: 30
        }
    ];
    
    var sum = result.reduce(function (prev, cur) {
        return cur.score + prev;
    }, 0);
    console.log(sum) //60
    复制代码
  6. 按属性对object分类

    var people = [
        { name: 'Alice', age: 21 },
        { name: 'Max', age: 20 },
        { name: 'Jane', age: 20 }
    ];
    
    function groupBy(objectArray, property) {
        return objectArray.reduce(function (acc, obj) {
            console.log(obj)
            var key = obj[property];
            if (!acc[key]) {
                acc[key] = [];
            }
            acc[key].push(obj);
            return acc;
        }, {});
    }
    
    var groupedPeople = groupBy(people, 'age');
    
    // { 
    // 20: [
    // { name: 'Max', age: 20 }, 
    // { name: 'Jane', age: 20 }
    // ], 
    // 21: [{ name: 'Alice', age: 21 }] 
    // }
    复制代码
  7. 功能型函数管道

    // Building-blocks to use for composition
    const double = x => x + x;
    const triple = x => 3 * x;
    const quadruple = x => 4 * x;
    
    // Function composition enabling pipe functionality
    const pipe = (...functions) => input => functions.reduce(
        (acc, fn) => fn(acc),
        input
    );
    
    // 还原函数
    // function pipe(...functions) {
    // return function (input) {
    // return functions.reduce(function (acc, fn) {
    // return fn(acc)
    // }, input)
    // }
    // }
    
    // Composed functions for multiplication of specific values
    const multiply6 = pipe(double, triple);
    const multiply9 = pipe(triple, triple);
    const multiply16 = pipe(quadruple, quadruple);
    const multiply24 = pipe(double, triple, quadruple);
    
    // Usage
    multiply6(6); // 36
    multiply9(9); // 81
    multiply16(16); // 256
    multiply24(10); // 240
    复制代码

② filter()方法

filter 为数组中的每一个元素调用一次 callback 函数,并利用全部使得 callback 返回 true 或 等价于 true 的值 的元素建立一个新数组。callback 只会在已经赋值的索引上被调用,对于那些已经被删除或者从未被赋值的索引不会被调用。那些没有经过 callback 测试的元素会被跳过,不会被包含在新数组中。

一、参数

callback

用来测试数组的每一个元素的函数。调用时使用参数 (element, index, array)。
复制代码

返回true表示保留该元素(经过测试),false则不保留。它接受三个参数:

**element**

	当前在数组中处理的元素。

**index**可选

	正在处理元素在数组中的索引。

**array**可选

	调用了`filter`的数组。
复制代码

thisArg可选

可选。执行 `callback` 时的用于 `this` 的值。
复制代码

二、返回值

一个新的经过测试的元素的集合的数组,若是没有经过测试则返回空数组

三、返回值

filter 为数组中的每一个元素调用一次 callback 函数,并利用全部使得 callback 返回 true 或 等价于 true 的值 的元素建立一个新数组。callback 只会在已经赋值的索引上被调用,对于那些已经被删除或者从未被赋值的索引不会被调用。那些没有经过 callback 测试的元素会被跳过,不会被包含在新数组中。

callback 被调用时传入三个参数:

  1. 元素的值
  2. 元素的索引
  3. 被遍历的数组

若是为 filter 提供一个 thisArg 参数,则它会被做为 callback 被调用时的 this 值。不然,callbackthis 值在非严格模式下将是全局对象,严格模式下为 undefinedcallback 最终观察到的this值是根据一般函数所看到的 "this"的规则肯定的。

filter 不会改变原数组,它返回过滤后的新数组。

filter 遍历的元素范围在第一次调用 callback 以前就已经肯定了。在调用 filter 以后被添加到数组中的元素不会被 filter 遍历到。若是已经存在的元素被改变了,则他们传入 callback 的值是 filter 遍历到它们那一刻的值。被删除或历来未被赋值的元素不会被遍历到。

四、示例

  • 筛选排除全部的小值
function isBigEnough(element) {
  return element >= 10;
}
var filtered = [12, 5, 8, 130, 44].filter(isBigEnough);
// filtered is [12, 130, 44]
复制代码
  • 过滤JSON中的无效条目
var arr = [
  { id: 15 },
  { id: -1 },
  { id: 0 },
  { id: 3 },
  { id: 12.2 },
  { },
  { id: null },
  { id: NaN },
  { id: 'undefined' }
];

var invalidEntries = 0;

function isNumber(obj) {
  return obj !== undefined && typeof(obj) === 'number' && !isNaN(obj);
}

function filterByID(item) {
  if (isNumber(item.id) && item.id !== 0) {
    return true;
  } 
  invalidEntries++;
  return false; 
}

var arrByID = arr.filter(filterByID);

console.log('Filtered Array\n', arrByID); 
// Filtered Array
// [{ id: 15 }, { id: -1 }, { id: 3 }, { id: 12.2 }]

console.log('Number of Invalid Entries = ', invalidEntries); 
// Number of Invalid Entries = 5
复制代码
  • 在数组中搜索
var fruits = ['apple', 'banana', 'grapes', 'mango', 'orange'];

/** * Array filters items based on search criteria (query) */
function filterItems(query) {
  return fruits.filter(function(el) {
      return el.toLowerCase().indexOf(query.toLowerCase()) > -1;
  })
}

console.log(filterItems('ap')); // ['apple', 'grapes']
console.log(filterItems('an')); // ['banana', 'mango', 'orange']
复制代码

  • GitHub: 欢迎Star wq93
相关文章
相关标签/搜索