10 個超級實用的 reduce 使用技巧

reduce 函數可以根據需要進行累加、過濾、分組、映射等操作,是一個非常強大的數組方法。在數據處理時使用的非常頻繁,很多複雜的邏輯如果用reduce去處理,都非常的簡潔,在實際的開發工作過程中,積累了一些常見又超級好用的 reduce 技巧的代碼片段,篩選瞭如下 10 個,以供大家參考

reduce 介紹

reduce 是數組的方法,可以對數組中的每個元素依次執行一個回調函數,從左到右依次累積計算出一個最終的值。其語法爲:

arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])

其中,callback 是每個元素執行的回調函數,其包含 4 個參數:

initialValue 是可選的,表示累積器的初始值。

reduce 函數的執行過程如下:

  1. 如果沒有提供 initialValue,則將數組的第一個元素作爲累積器的初始值,否則將 initialValue 作爲累積器的初始值。

  2. 從數組的第二個元素開始,依次對數組中的每個元素執行回調函數。

  3. 回調函數的返回值作爲下一次回調函數執行時的累積器的值。

  4. 對數組中的每個元素執行完回調函數後,reduce 函數返回最後一次回調函數的返回值,即最終的累積值。

計算數組中每個元素出現的次數

const fruits = ['apple''banana''apple''orange''banana''apple'];
const count = fruits.reduce((accumulator, currentValue) ={
  accumulator[currentValue] = (accumulator[currentValue] || 0) + 1;
  return accumulator;
}{});
console.log(count); // Output: { apple: 3, banana: 2, orange: 1 }

拍平嵌套數組

const nestedArray = [[1, 2][3, 4][5, 6]];
const flattenedArray = nestedArray.reduce((accumulator, currentValue) => accumulator.concat(currentValue)[]);
console.log(flattenedArray); // Output: [1, 2, 3, 4, 5, 6]

按條件分組

const people = [
  { name: 'Alice', age: 25 },
  { name: 'Bob', age: 30 },
  { name: 'Charlie', age: 35 },
  { name: 'David', age: 25 },
  { name: 'Emily', age: 30 }
];
const groupedPeople = people.reduce((accumulator, currentValue) ={
  const key = currentValue.age;
  if (!accumulator[key]) {
    accumulator[key] = [];
  }
  accumulator[key].push(currentValue);
  return accumulator;
}{});
console.log(groupedPeople);
// Output: {
//   25: [{ name: 'Alice', age: 25 }{ name: 'David', age: 25 }],
//   30: [{ name: 'Bob', age: 30 }{ name: 'Emily', age: 30 }],
//   35: [{ name: 'Charlie', age: 35 }]
// }

將多個數組合併爲一個對象

const keys = ['name''age''gender'];
const values = ['Alice', 25, 'female'];
const person = keys.reduce((accumulator, currentValue, index) ={
    accumulator[currentValue] = values[index];
    return accumulator;
  }{});
console.log(person); // Output: { name: 'Alice', age: 25, gender: 'female' }

將字符串轉換爲對象

const str = 'key1=value1&key2=value2&key3=value3';
const obj = str.split('&').reduce((accumulator, currentValue) ={
  const [key, value] = currentValue.split('=');
  accumulator[key] = value;
  return accumulator;
}{});
console.log(obj); 
// Output: { key1: 'value1', key2: 'value2', key3: 'value3' }

將對象轉換爲查詢字符串

const params = { foo: "bar", baz: 42 };
const queryString = Object.entries(params).reduce((acc, [key, value]) ={
  return `${acc}${key}=${value}&`;
}"?").slice(0, -1);
console.log(queryString); // "?foo=bar&baz=42"

打印斐波那契數列

const fibonacci = n ={
  return [...Array(n)].reduce((accumulator, currentValue, index) ={
    if (index < 2) {
      accumulator.push(index);
    } else {
      accumulator.push(accumulator[index - 1] + accumulator[index - 2]);
    }
    return accumulator;
  }[]);
};
console.log(fibonacci(10)); // Output: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

檢查字符串是否是迴文字符串

const str = 'racecar';
const isPalindrome = str.split('').reduce((accumulator, currentValue, index, array) ={
  return accumulator && currentValue === array[array.length - index - 1];
}true);
console.log(isPalindrome); // Output: true

檢查括號是否匹配

const str = "(()()())";
const balanced = str.split("").reduce((acc, cur) ={
  if (cur === "(") {
    acc++;
  } else if (cur === ")") {
    acc--;
  }
  return acc;
}, 0) === 0;
console.log(balanced); // true

遞歸獲取對象屬性

const user = {
  info: {
    name: "Jason",
    address: { home: "Shaanxi", company: "Xian" },
  },
};
function get(config, path, defaultVal) {
  return path.split('.').reduce((config, name) => config[name], config) || defaultVal;
  return fallback;
}
get(user, "info.name"); // Jason
get(user, "info.address.home"); // Shaanxi
get(user, "info.address.company"); // Xian
get(user, "info.address.abc""default"); // default

手寫 reduce

可以通過手寫一個簡單的 reduce 函數來更好地理解它的實現原理:

function myReduce(arr, callback, initialValue) {
  let accumulator = initialValue === undefined ? arr[0] : initialValue;
  for (let i = initialValue === undefined ? 1 : 0; i < arr.length; i++) {
    accumulator = callback(accumulator, arr[i], i, arr);
  }
  return accumulator;
}

上面的代碼中,myReduce 函數接受 3 個參數:要執行 reduce 操作的數組 arr、回調函數 callback 和累積器的初始值 initialValue。如果沒有提供初始值,則將數組的第一個元素作爲累積器的初始值。

接下來,在循環中,如果有 initialValue,則從第一個元素開始遍歷 callback,此時 callabck 的第二個參數是從數組的第一項開始的;如果沒有 initialValue,則從第二個元素開始遍歷 callback,此時 callback 的第二個參數是從數組的第二項開始的從數組的第二個元素開始,依次對數組中的每個元素執行回調函數,並將返回值作爲下一次回調函數執行時的累積器的值。

最後,myReduce 函數返回最後一次回調函數的返回值,即最終的累積值。

這個簡易的 reduce 函數並沒有考慮很多邊界情況和複雜的應用場景,但是可以幫助我們更好地理解 reduce 函數的實現原理。

關於本文

作者:shichuan

https://juejin.cn/post/7224043114360225847

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/wq2Fzi3CiqVQbuASUktr6Q