From 68a0467b225cdcf072526490374d29a21977e8a1 Mon Sep 17 00:00:00 2001 From: Masahiro FUJIMOTO Date: Sat, 11 Sep 2021 15:36:23 +0900 Subject: Global_Objects/Array/Reduce を更新 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 2021/08/16 時点の英語版に同期 --- .../global_objects/array/reduce/index.html | 590 --------------------- .../reference/global_objects/array/reduce/index.md | 549 +++++++++++++++++++ 2 files changed, 549 insertions(+), 590 deletions(-) delete mode 100644 files/ja/web/javascript/reference/global_objects/array/reduce/index.html create mode 100644 files/ja/web/javascript/reference/global_objects/array/reduce/index.md (limited to 'files/ja/web/javascript/reference') diff --git a/files/ja/web/javascript/reference/global_objects/array/reduce/index.html b/files/ja/web/javascript/reference/global_objects/array/reduce/index.html deleted file mode 100644 index bc07a5506e..0000000000 --- a/files/ja/web/javascript/reference/global_objects/array/reduce/index.html +++ /dev/null @@ -1,590 +0,0 @@ ---- -title: Array.prototype.reduce() -slug: Web/JavaScript/Reference/Global_Objects/Array/reduce -tags: - - Array - - Array method - - ECMAScript 5 - - JavaScript - - Method - - Prototype - - Reduce - - Reference - - メソッド -translation_of: Web/JavaScript/Reference/Global_Objects/Array/Reduce ---- -
{{JSRef}}
- -

reduce() メソッドは、配列の各要素に対して (引数で与えられた) reducer 関数を実行して、単一の出力値を生成します。

- -
{{EmbedInteractiveExample("pages/js/array-reduce.html")}}
- - - -

reducer 関数は 4 つの引数を取ります。

- -
    -
  1. アキュムレーター (acc)
  2. -
  3. 現在値 (cur)
  4. -
  5. 現在の添字 (idx)
  6. -
  7. 元の配列 (src)
  8. -
- -

reducer 関数の返値はアキュムレーターに代入され、配列内の各反復に対してこの値を記憶します。最終的に単一の結果値になります。

- -

構文

- -
arr.reduce(callback( accumulator, currentValue[, index[, array]] ) {
-  // return result from executing something for accumulator or currentValue
-}[, initialValue]);
- -

引数

- -
-
callback
-
-

配列のすべての要素 (initialValue が提供されなかった場合は、最初を除く) に対して実行される関数です。

- -

これは 4 つの引数を取ります。

- -
-
accumulator
-
callback の返値を蓄積するアキュームレーターです。これは、コールバックの前回の呼び出しで返された値、あるいは initialValue が指定されている場合はその値となります (以下を参照ください)。
-
currentValue
-
現在処理されている配列の要素です。
-
index {{optional_inline}}
-
現在処理されている配列要素のインデックスです。initialValue が指定された場合はインデックス 0 から、そうでない場合はインデックス 1 から開始します。
-
array {{optional_inline}}
-
reduce() が呼び出された配列です。
-
-
-
initialValue {{optional_inline}}
-
callback の最初の呼び出しの最初の引数として使用する値。initialValue が与えられなかった場合、配列の最初の要素がアキュムレーターの初期値として使用され、currentValue としてスキップされます。空の配列に対して reduce() を呼び出した際、initialValue が指定されていないと {{jsxref("TypeError")}} が発生します。
-
- -

返値

- -

畳み込みによって得られた 1 つの値です。

- -

解説

- -

reduce() メソッドは、配列に存在する各要素ごとに対して、callback 関数を次の 4 つの引数を渡しながら一度だけ実行します。

- -
    -
  1. accumulator
  2. -
  3. currentValue
  4. -
  5. currentIndex
  6. -
  7. array
  8. -
- -

コールバックが最初に呼び出されたとき、accumulatorcurrentValue が 2 つの値になります。initialValuereduce() の呼び出しで提供されていた場合、accumulatorinitialValue と等しくなり、currentValue は配列の最初の値と等しくなります。initialValue が提供されなかった場合は、accumulator は配列の最初の値と等しくなり、currentValue は 2番目の値と等しくなります。

- -
-

注: initialValue が指定されなかった場合は、reduce() は最初の要素を飛ばしてインデックス 1 から実行されます。initialValue が指定されていたらインデックス 0 から開始します。

-
- -

配列が空で initialValue が指定されなかった場合は {{jsxref("TypeError")}} が発生します。

- -

配列が (位置に関わらず) 1 つの要素しか持たず、initialValue が指定されなかった場合、または initialValue が指定されていても配列が空だった場合、callback が実行されずに要素が返却されます。

- -

initialValue を指定しなかった場合、下記の例のような 4 種類の結果が発生しうるため、initialValue を指定する方が通常は安全です。

- -
let maxCallback = ( acc, cur ) => Math.max( acc.x, cur.x );
-let maxCallback2 = ( max, cur ) => Math.max( max, cur );
-
-// reduce without initialValue
-[ { x: 2 }, { x: 22 }, { x: 42 } ].reduce( maxCallback ); // NaN
-[ { x: 2 }, { x: 22 }            ].reduce( maxCallback ); // 22
-[ { x: 2 }                       ].reduce( maxCallback ); // { x: 2 }
-[                                ].reduce( maxCallback ); // TypeError
-
-// map & reduce with initialValue; better solution, also works for empty or larger arrays
-[ { x: 22 }, { x: 42 } ].map( el => el.x )
-                        .reduce( maxCallback2, -Infinity );
-
- -

reduce() はどう動くか

- -

次のコードのように reduce() を使用した場合について見てみましょう。

- -
[0, 1, 2, 3, 4].reduce(function(accumulator, currentValue, currentIndex, array) {
-  return accumulator + currentValue
-})
-
- -

コールバック関数は 4 回呼び出され、各回の引数の内容は以下のようになっています。

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
callback の反復accumulatorcurrentValuecurrentIndexarray返値
初回の呼出し011[0, 1, 2, 3, 4]1
2 回目の呼出し122[0, 1, 2, 3, 4]3
3 回目の呼出し333[0, 1, 2, 3, 4]6
4 回目の呼出し644[0, 1, 2, 3, 4]10
- -

reduce() の返値は、コールバック呼び出しの最後の返値である (10) となるでしょう。

- -

通常の関数の代わりに{{jsxref("Functions/Arrow_functions", "アロー関数","",1)}}を指定することができます。下記のコードは上述のコードと同じ結果を返します。

- -
[0, 1, 2, 3, 4].reduce( (accumulator, currentValue, currentIndex, array) => accumulator + currentValue )
-
- -

reduce() の 2 つ目の引数に初期値を設定した場合は、コールバック各回の内部的な動作はこのようになります。

- -
[0, 1, 2, 3, 4].reduce((accumulator, currentValue, currentIndex, array) => {
-    return accumulator + currentValue
-}, 10)
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
callback の反復accumulatorcurrentValuecurrentIndexarray返値
初回の呼出し1000[0, 1, 2, 3, 4]10
2 回目の呼出し1011[0, 1, 2, 3, 4]11
3 回目の呼出し1122[0, 1, 2, 3, 4]13
4 回目の呼出し1333[0, 1, 2, 3, 4]16
5 回目の呼出し1644[0, 1, 2, 3, 4]20
- -

この場合の reduce() の返値は 20 となります。

- -

ポリフィル

- -
// Production steps of ECMA-262, Edition 5, 15.4.4.21
-// Reference: http://es5.github.io/#x15.4.4.21
-// https://tc39.github.io/ecma262/#sec-array.prototype.reduce
-if (!Array.prototype.reduce) {
-  Object.defineProperty(Array.prototype, 'reduce', {
-    value: function(callback /*, initialValue*/) {
-      if (this === null) {
-        throw new TypeError( 'Array.prototype.reduce ' +
-          'called on null or undefined' );
-      }
-      if (typeof callback !== 'function') {
-        throw new TypeError( callback +
-          ' is not a function');
-      }
-
-      // 1. Let O be ? ToObject(this value).
-      var o = Object(this);
-
-      // 2. Let len be ? ToLength(? Get(O, "length")).
-      var len = o.length >>> 0;
-
-      // Steps 3, 4, 5, 6, 7
-      var k = 0;
-      var value;
-
-      if (arguments.length >= 2) {
-        value = arguments[1];
-      } else {
-        while (k < len && !(k in o)) {
-          k++;
-        }
-
-        // 3. If len is 0 and initialValue is not present,
-        //    throw a TypeError exception.
-        if (k >= len) {
-          throw new TypeError( 'Reduce of empty array ' +
-            'with no initial value' );
-        }
-        value = o[k++];
-      }
-
-      // 8. Repeat, while k < len
-      while (k < len) {
-        // a. Let Pk be ! ToString(k).
-        // b. Let kPresent be ? HasProperty(O, Pk).
-        // c. If kPresent is true, then
-        //    i.  Let kValue be ? Get(O, Pk).
-        //    ii. Let accumulator be ? Call(
-        //          callbackfn, undefined,
-        //          « accumulator, kValue, k, O »).
-        if (k in o) {
-          value = callback(value, o[k], k, o);
-        }
-
-        // d. Increase k by 1.
-        k++;
-      }
-
-      // 9. Return accumulator.
-      return value;
-    }
-  });
-}
-
- -
-

警告: {{jsxref("Object.defineProperty()")}} に対応していない本当に時代遅れの JavaScript エンジンに対応する必要がある場合、Array.prototype列挙不可能にすることはできないので、メソッドのポリフィルを使わない方が良いでしょう。

-
- -

- -

配列内の値の合計値を出す

- -
let sum = [0, 1, 2, 3].reduce(function (accumulator, currentValue) {
-  return accumulator + currentValue
-}, 0)
-// sum is 6
-
-
- -

また、アロー関数を用いて書くことも出来ます。

- -
let total = [ 0, 1, 2, 3 ].reduce(
-  ( accumulator, currentValue ) => accumulator + currentValue,
-  0
-)
- -

オブジェクトの配列の値の合計値を出す

- -

オブジェクトの配列に含まれた値の合計値を出すには、すべての項目を関数内で取得できるようにするために initialValue を指定する必要があります

- -
let initialValue = 0
-let sum = [{x: 1}, {x: 2}, {x: 3}].reduce(function (accumulator, currentValue) {
-    return accumulator + currentValue.x
-}, initialValue)
-
-console.log(sum) // logs 6
-
- -

また、アロー関数を用いて書くことも出来ます。

- -
let initialValue = 0
-let sum = [{x: 1}, {x: 2}, {x: 3}].reduce(
-    (accumulator, currentValue) => accumulator + currentValue.x
-    , initialValue
-)
-
-console.log(sum) // logs 6
- -

二次元配列を一次元配列にする

- -
let flattened = [[0, 1], [2, 3], [4, 5]].reduce(
-  function(accumulator, currentValue) {
-    return accumulator.concat(currentValue)
-  },
-  []
-)
-// flattened is [0, 1, 2, 3, 4, 5]
-
- -

また、アロー関数を用いて書くことも出来ます。

- -
let flattened = [[0, 1], [2, 3], [4, 5]].reduce(
-  ( accumulator, currentValue ) => accumulator.concat(currentValue),
-  []
-)
-
- -

オブジェクトの値のインスタンスを数える

- -
let names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice']
-
-let countedNames = names.reduce(function (allNames, name) {
-  if (name in allNames) {
-    allNames[name]++
-  }
-  else {
-    allNames[name] = 1
-  }
-  return allNames
-}, {})
-// countedNames is:
-// { 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 }
-
- -

プロパティによってオブジェクトをグループ化する

- -
let people = [
-  { name: 'Alice', age: 21 },
-  { name: 'Max', age: 20 },
-  { name: 'Jane', age: 20 }
-];
-
-function groupBy(objectArray, property) {
-  return objectArray.reduce(function (acc, obj) {
-    let key = obj[property]
-    if (!acc[key]) {
-      acc[key] = []
-    }
-    acc[key].push(obj)
-    return acc
-  }, {})
-}
-
-let groupedPeople = groupBy(people, 'age')
-// groupedPeople is:
-// {
-//   20: [
-//     { name: 'Max', age: 20 },
-//     { name: 'Jane', age: 20 }
-//   ],
-//   21: [{ name: 'Alice', age: 21 }]
-// }
-
- -

スプレッド演算子と initialValue を使ってオブジェクトの配列に含まれる配列を結合させる

- -
// friends - an array of objects
-// where object field "books" is a list of favorite books
-let friends = [{
-  name: 'Anna',
-  books: ['Bible', 'Harry Potter'],
-  age: 21
-}, {
-  name: 'Bob',
-  books: ['War and peace', 'Romeo and Juliet'],
-  age: 26
-}, {
-  name: 'Alice',
-  books: ['The Lord of the Rings', 'The Shining'],
-  age: 18
-}]
-
-// allbooks - list which will contain all friends' books +
-// additional list contained in initialValue
-let allbooks = friends.reduce(function(accumulator, currentValue) {
-  return [...accumulator, ...currentValue.books]
-}, ['Alphabet'])
-
-// allbooks = [
-//   'Alphabet', 'Bible', 'Harry Potter', 'War and peace',
-//   'Romeo and Juliet', 'The Lord of the Rings',
-//   'The Shining'
-// ]
- -

配列内の重複要素を除去する

- -
-

注: {{jsxref("Set")}} と {{jsxref("Array.from()")}} に対応している環境を使っている場合、let orderedArray = Array.from(new Set(myArray)) を使うことで重複要素を除去された配列を取得することができます。

-
- -
let myArray = ['a', 'b', 'a', 'b', 'c', 'e', 'e', 'c', 'd', 'd', 'd', 'd']
-let myOrderedArray = myArray.reduce(function (accumulator, currentValue) {
-  if (accumulator.indexOf(currentValue) === -1) {
-    accumulator.push(currentValue)
-  }
-  return accumulator
-}, [])
-
-console.log(myOrderedArray)
- -

.filter().map() を .reduce() で置き換える

- -

{{jsxref("Array.filter()")}} を使用した後で {{jsxref("Array.map()")}} を使用すると配列を二度走査しますが、{{jsxref("Array.reduce()")}} では同じ効果を一度の操作で実現することができ、もっと効率的です。(for ループが好きなのであれば、{{jsxref("Array.forEach()")}} で一度の操作で filter と map を行うことができます)。

- -
const numbers = [-5, 6, 2, 0,];
-
-const doubledPositiveNumbers = numbers.reduce((accumulator, currentValue) => {
-  if (currentValue > 0) {
-    const doubled = currentValue * 2;
-    accumulator.push(doubled);
-  }
-  return accumulator;
-}, []);
-
-console.log(doubledPositiveNumbers); // [12, 4]
- -

シーケンス上の Promise を動かす

- -
/**
- * Runs promises from array of functions that can return promises
- * in chained manner
- *
- * @param {array} arr - promise arr
- * @return {Object} promise object
- */
-function runPromiseInSequence(arr, input) {
-  return arr.reduce(
-    (promiseChain, currentFunction) => promiseChain.then(currentFunction),
-    Promise.resolve(input)
-  )
-}
-
-// promise function 1
-function p1(a) {
-  return new Promise((resolve, reject) => {
-    resolve(a * 5)
-  })
-}
-
-// promise function 2
-function p2(a) {
-  return new Promise((resolve, reject) => {
-    resolve(a * 2)
-  })
-}
-
-// function 3  - will be wrapped in a resolved promise by .then()
-function f3(a) {
- return a * 3
-}
-
-// promise function 4
-function p4(a) {
-  return new Promise((resolve, reject) => {
-    resolve(a * 4)
-  })
-}
-
-const promiseArr = [p1, p2, f3, p4]
-runPromiseInSequence(promiseArr, 10)
-  .then(console.log)   // 1200
-
- -

パイプによって関数を合成する

- -
// 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
-)
-
-// 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
-
-
- -

reduce を使って map メソッドを書く

- -
if (!Array.prototype.mapUsingReduce) {
-  Array.prototype.mapUsingReduce = function(callback, thisArg) {
-    return this.reduce(function(mappedArray, currentValue, index, array) {
-      mappedArray[index] = callback.call(thisArg, currentValue, index, array)
-      return mappedArray
-    }, [])
-  }
-}
-
-[1, 2, , 3].mapUsingReduce(
-  (currentValue, index, array) => currentValue + index + array.length
-) // [5, 7, , 10]
-
-
- -

仕様

- - - - - - - - - - - - -
仕様書
{{SpecName('ESDraft', '#sec-array.prototype.reduce', 'Array.prototype.reduce()')}}
- -

ブラウザーの互換性

- -
-

{{Compat("javascript.builtins.Array.reduce")}}

-
- -

関連情報

- - diff --git a/files/ja/web/javascript/reference/global_objects/array/reduce/index.md b/files/ja/web/javascript/reference/global_objects/array/reduce/index.md new file mode 100644 index 0000000000..86a45268bf --- /dev/null +++ b/files/ja/web/javascript/reference/global_objects/array/reduce/index.md @@ -0,0 +1,549 @@ +--- +title: Array.prototype.reduce() +slug: Web/JavaScript/Reference/Global_Objects/Array/reduce +tags: + - Array + - 配列メソッド + - ECMAScript 5 + - JavaScript + - メソッド + - プロトタイプ + - Reduce + - リファレンス + - ポリフィル +browser-compat: javascript.builtins.Array.reduce +translation_of: Web/JavaScript/Reference/Global_Objects/Array/reduce +--- +{{JSRef}} + +**`reduce()`** メソッドは、配列のそれぞれの要素に対してユーザーが提供した「縮小」コールバック関数を呼び出します。その際、直前の要素における計算結果の返値を渡します。配列のすべての要素に対して縮小関数を実行した結果が単一の値が最終結果になります。 + +`reduce()` で一番わかりやすいのは、配列のすべての要素の和を返す場合でしょう。 + +縮小関数は配列を要素ごとに走査し、それぞれの段階で、前の段階の結果に現在の配列の値を加えていきます (この結果は、それ以前のすべての段階を合算したものです)。 + +次のインタラクティブサンプルで紹介します。 + +{{EmbedInteractiveExample("pages/js/array-reduce.html")}} + +## 構文 + +```js +// アロー関数 +reduce((previousValue, currentValue) => { ... } ) +reduce((previousValue, currentValue, currentIndex) => { ... } ) +reduce((previousValue, currentValue, currentIndex, array) => { ... } ) +reduce((previousValue, currentValue, currentIndex, array) => { ... }, initialValue) + +// コールバック関数 +reduce(callbackFn) +reduce(callbackFn, initialValue) + +// インラインコールバック関数 +reduce(function callbackFn(previousValue, currentValue) { ... }) +reduce(function callbackFn(previousValue, currentValue, currentIndex) { ... }) +reduce(function callbackFn(previousValue, currentValue, currentIndex, array){ ... }) +reduce(function callbackFn(previousValue, currentValue, currentIndex, array) { ... }, initialValue) +``` + +### 引数 + +- `callbackFn` + - : 4 つの引数を取る「縮小」関数です。 + - *previousValue* (前回の `callbackfn` の呼び出し結果の値) + - *currentValue* (現在の要素の値) + - *currentIndex* (現在の位置) {{optional_inline}} + - *array* (走査する配列) {{optional_inline}} + +- `initialValue` {{optional_inline}} + - : コールバックが初めて呼び出されたときの *previousValue* の初期値です。 `initialValue` が指定された場合は、 *currentValue* も配列の最初の値に初期化されます。 `initialValue` が指定され*なかった*場合、 *previousValue* は配列の最初の値で初期化され、 *currentValue* は配列の 2 番目の値で初期化されます。 + +### 返値 + +配列全体にわたって「縮小」コールバック関数を実行した結果の値です。 + +### 例外 + +{{jsxref("TypeError")}}: 配列に要素がなく、かつ `initialValue` が提供されなかった場合に発生します。 + +## 解説 + +ECMAScript の仕様書は、 `reduce()` の動作を次のように記述しています。 + +> *callbackfn* は、4 つの引数を取る関数でなければなりません。 `reduce` は、配列の最初の要素の後の各要素に対して、昇順にコールバックを関数として呼び出します。 +> +> *callbackfn* は次の 4 つの引数で呼び出されます。 +> +> - the *previousValue* (前回の *callbackfn* の呼び出し結果の値) +> - the *currentValue* (現在の要素の値) +> - the *currentIndex* +> - 走査中のオブジェクト +> そのコールバックが最初に呼び出されるとき、 *previousValue* と *currentValue* は以下の 2 通りのうちのどちらかになります。 +> - *initialValue* が `reduce` の呼び出しによって与えられた場合、 *previousValue* は to *initialValue* と同じになり、 *currentValue* は配列の最初の値と等しくなります。 +> - *initialValue* が与えられていない場合は、 *previousValue* は配列の最初の値と同じになり、 *currentValue* は 2 番目の値と同じになります。 +> 配列に要素がなく、かつ *initialValue* が与えられていない場合は {{jsxref("TypeError")}} が発生します。 +> +> `reduce` は、呼び出されたオブジェクトを直接は変更しませんが、 *callbackfn* の呼び出しによってオブジェクトが変更される可能性はあります。 +> +> `reduce` で処理される要素の範囲は、 *callbackfn* が最初に呼び出される前に設定されます。 `reduce` の呼び出しが始まった後に配列に追加された要素は、 *callbackfn* が処理することはありません。配列の既存の要素が変更された場合、 *callbackfn* には `reduce` がその値を処理する時点の値が渡されます。 `reduce` が呼び出された後、処理されるまでに削除された要素は処理されません。 + +配列が (位置に関わらず) 1 つの要素しか持たず、*initialValue* が指定されなかった場合、または *initialValue* が指定されていても配列が空だった場合、 _`callbackfn`_ は*実行されずに*要素が返却されます。 + +*initialValue* が提供され、配列が空でない場合、 reduce メソッドは常に 0 の位置コールバック関数を呼び出し始めます。 + +*initialValue* が提供されなかった場合、 reduce メソッドは、次の例に示すように、長さが 1 より大きい配列、長さが 1 の配列、長さが 0 の配列に対して異なる動作をします。 + +```js +const getMax = (a, b) => Math.max(a, b); + +// コールバックは 0 の位置から配列内の全要素に対して呼び出される +[1, 100].reduce(getMax, 50); // 100 +[ 50].reduce(getMax, 10); // 50 + +// コールバックは 1 の位置に対して 1 度だけ呼び出される +[1, 100].reduce(getMax); // 100 + +// コールバックは呼び出されない +[ 50].reduce(getMax); // 50 +[ ].reduce(getMax, 1); // 1 + +[ ].reduce(getMax); // TypeError +``` + +### reduce() の動作 + +`reduce()` を以下のように使うことを想像してください。 + +```js +[0, 1, 2, 3, 4].reduce(function(previousValue, currentValue, currentIndex, array) { + return previousValue + currentValue +}) +``` + +コールバック関数は 4 回呼び出され、各回の引数の内容は以下のようになります。 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ callback の反復処理 + + previousValue + + currentValue + + currentIndex + + array + 返値
初回の呼出し011[0, 1, 2, 3, 4]1
2 回目の呼出し122[0, 1, 2, 3, 4]3
3 回目の呼出し333[0, 1, 2, 3, 4]6
4 回目の呼出し644[0, 1, 2, 3, 4]10
+ +`reduce()` の返値は、コールバック呼び出しの最後の返値である (`10`) となるでしょう。 + +通常の関数の代わりに{{jsxref("Functions/Arrow_functions", "アロー関数","",1)}}を指定することができます。下記のコードは上記のコードと同じ結果を返します。 + +```js +[0, 1, 2, 3, 4].reduce( (previousValue, currentValue, currentIndex, array) => previousValue + currentValue ) +``` + +*initialValue* を `reduce()` の 2 つ目の引数に渡した場合は、結果は次のようになります。 + +```js +[0, 1, 2, 3, 4].reduce((previousValue, currentValue, currentIndex, array) => { + return previousValue + currentValue +}, 10) +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ callback の反復処理 + + previousValue + + currentValue + + currentIndex + + array + 返値
初回の呼出し1000[0, 1, 2, 3, 4]10
2 回目の呼出し1011[0, 1, 2, 3, 4]11
3 回目の呼出し1122[0, 1, 2, 3, 4]13
4 回目の呼出し1333[0, 1, 2, 3, 4]16
5 回目の呼出し1644[0, 1, 2, 3, 4]20
+ +この場合の `reduce()` の返値は `20` となります。

+ +## 例 + +### 配列内の値の合計値を出す + +```js +let sum = [0, 1, 2, 3].reduce(function (previousValue, currentValue) { + return previousValue + currentValue +}, 0) +// sum is 6 +``` + +また、アロー関数を用いて書くこともできます。 + +```js +let total = [ 0, 1, 2, 3 ].reduce( + ( previousValue, currentValue ) => previousValue + currentValue, + 0 +) +``` + +### オブジェクトの配列の値の合計値を出す + +オブジェクトの配列に含まれた値の合計値を出すには、すべての項目を関数内で取得できるようにするために *initialValue* を指定する**必要があります**。 + +```js +let initialValue = 0 +let sum = [{x: 1}, {x: 2}, {x: 3}].reduce(function (previousValue, currentValue) { + return previousValue + currentValue.x +}, initialValue) + +console.log(sum) // logs 6 +``` + +また、アロー関数を用いて書くこともできます。 + +```js +let initialValue = 0 +let sum = [{x: 1}, {x: 2}, {x: 3}].reduce( + (previousValue, currentValue) => previousValue + currentValue.x + , initialValue +) + +console.log(sum) // logs 6 +``` + +### 二次元配列を一次元配列にする + +```js +let flattened = [[0, 1], [2, 3], [4, 5]].reduce( + function(previousValue, currentValue) { + return previousValue.concat(currentValue) + }, + [] +) +// flattened is [0, 1, 2, 3, 4, 5] +``` + +また、アロー関数を用いて書くこともできます。 + +```js +let flattened = [[0, 1], [2, 3], [4, 5]].reduce( + ( previousValue, currentValue ) => previousValue.concat(currentValue), + [] +) +``` + +### オブジェクトの値のインスタンスを数える + +```js +let names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'] + +let countedNames = names.reduce(function (allNames, name) { + if (name in allNames) { + allNames[name]++ + } + else { + allNames[name] = 1 + } + return allNames +}, {}) +// countedNames is: +// { 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 } +``` + +### プロパティによってオブジェクトをグループ化 + +```js +let people = [ + { name: 'Alice', age: 21 }, + { name: 'Max', age: 20 }, + { name: 'Jane', age: 20 } +]; + +function groupBy(objectArray, property) { + return objectArray.reduce(function (acc, obj) { + let key = obj[property] + if (!acc[key]) { + acc[key] = [] + } + acc[key].push(obj) + return acc + }, {}) +} + +let groupedPeople = groupBy(people, 'age') +// groupedPeople is: +// { +// 20: [ +// { name: 'Max', age: 20 }, +// { name: 'Jane', age: 20 } +// ], +// 21: [{ name: 'Alice', age: 21 }] +// } +``` + +### スプレッド演算子と initialValue を使ってオブジェクトの配列に含まれる配列を結合させる + +```js +// friends - an array of objects +// where object field "books" is a list of favorite books +let friends = [{ + name: 'Anna', + books: ['Bible', 'Harry Potter'], + age: 21 +}, { + name: 'Bob', + books: ['War and peace', 'Romeo and Juliet'], + age: 26 +}, { + name: 'Alice', + books: ['The Lord of the Rings', 'The Shining'], + age: 18 +}] + +// allbooks - list which will contain all friends' books + +// additional list contained in initialValue +let allbooks = friends.reduce(function(previousValue, currentValue) { + return [...previousValue, ...currentValue.books] +}, ['Alphabet']) + +// allbooks = [ +// 'Alphabet', 'Bible', 'Harry Potter', 'War and peace', +// 'Romeo and Juliet', 'The Lord of the Rings', +// 'The Shining' +// ] +``` + +### 配列内の重複要素を除去する + +> **Note:** {{jsxref("Set")}} と {{jsxref("Array.from()")}} に対応している環境を使っている場合は、`let orderedArray = Array.from(new Set(myArray))` を使うことで重複要素を除去された配列を取得することができます。 + +```js +let myArray = ['a', 'b', 'a', 'b', 'c', 'e', 'e', 'c', 'd', 'd', 'd', 'd'] +let myArrayWithNoDuplicates = myArray.reduce(function (previousValue, currentValue) { + if (previousValue.indexOf(currentValue) === -1) { + previousValue.push(currentValue) + } + return previousValue +}, []) + +console.log(myArrayWithNoDuplicates) +``` + +### .filter().map() を .reduce() で置き換える + +{{jsxref("Array.filter()")}} を使用した後で {{jsxref("Array.map()")}} を使用すると配列を二度走査しますが、{{jsxref("Array.reduce()")}} では同じ効果を一度の操作で実現することができ、もっと効率的です。(for ループが好きなのであれば、{{jsxref("Array.forEach()")}} で一度の操作で filter と map を行うことができます)。 + +```js +const numbers = [-5, 6, 2, 0,]; + +const doubledPositiveNumbers = numbers.reduce((previousValue, currentValue) => { + if (currentValue > 0) { + const doubled = currentValue * 2; + previousValue.push(doubled); + } + return previousValue; +}, []); + +console.log(doubledPositiveNumbers); // [12, 4] +``` + +### シーケンス上の Promise を動かす + +```js +/** + * Runs promises from array of functions that can return promises + * in chained manner + * + * @param {array} arr - promise arr + * @return {Object} promise object + */ +function runPromiseInSequence(arr, input) { + return arr.reduce( + (promiseChain, currentFunction) => promiseChain.then(currentFunction), + Promise.resolve(input) + ) +} + +// promise function 1 +function p1(a) { + return new Promise((resolve, reject) => { + resolve(a * 5) + }) +} + +// promise function 2 +function p2(a) { + return new Promise((resolve, reject) => { + resolve(a * 2) + }) +} + +// function 3 - will be wrapped in a resolved promise by .then() +function f3(a) { + return a * 3 +} + +// promise function 4 +function p4(a) { + return new Promise((resolve, reject) => { + resolve(a * 4) + }) +} + +const promiseArr = [p1, p2, f3, p4] +runPromiseInSequence(promiseArr, 10) + .then(console.log) // 1200 +``` + +### パイプによって関数を合成する + +```js +// 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 +) + +// 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 +``` + +### reduce を使って map メソッドを書く + +```js +if (!Array.prototype.mapUsingReduce) { + Array.prototype.mapUsingReduce = function(callback, initialValue) { + return this.reduce(function(mappedArray, currentValue, currentIndex, array) { + mappedArray[index] = callback.call(initialValue, currentValue, currentIndex, array) + return mappedArray + }, []) + } +} + +[1, 2, , 3].mapUsingReduce( + (currentValue, currentIndex, array) => currentValue + currentIndex + array.length +) // [5, 7, , 10] +``` + +## 仕様書 + +{{Specifications}} + +## ブラウザーの互換性 + +{{Compat}} + +## 関連情報 + +- `Array.prototype.reduce` のポリフィルが [`core-js`](https://github.com/zloirock/core-js#ecmascript-array) で利用できます +- {{jsxref("Array.prototype.reduceRight()")}} -- cgit v1.2.3-54-g00ecf