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
相關文章
相關標籤/搜索