[JavaScript] reduce で配列を合成する際のベストプラクティス考

概要

  • JavaScript で reduce により配列を合成する際、どの方法が速いのかを調べてみました。

比較対象

  • 以下の実装を高階関数で書き替えるのを想定してます。
  • 高階関数使用時の比較なので、「for 文の方が速いかどうか」は、今回の調査対象外です。
const info = {
  a: [11, 13, 15],
  b: [22, 24, 26],
  c: [33, 35, 37],
}
const a = ['a', 'b', 'c']

const results = []
for (const i in a) {
  results.push(...info[a[i]])
}

console.log(results)
// [11, 13, 15, 22, 24, 26, 33, 35, 37]

候補

  • [].push()
;['a', 'b', 'c']
  .map(key => info[key])
  .reduce(
    (stack, it) => {
      stack.push(...it)
      return stack
    },
    []
  )
  • [].concat()
;['a', 'b', 'c']
  .map(key => info[key])
  .reduce((stack, it) => stack.concat(it))
  • [].push() + ,
;['a', 'b', 'c']
  .map(key => info[key])
  .reduce((stack, it) => (stack.push(...it), stack))
  • flatMap
;['a', 'b', 'c'].flatMap(key => info[key])

比較

  • 100万回ほど回してみました。
const info = {
  a: [11, 13, 15],
  b: [22, 24, 26],
  c: [33, 35, 37],
}
const a = ['a', 'b', 'c']
const m = 100 * 10000
console.time('push()')
for (let i = 0; i < m; ++i) {
  a.map(key => info[key])
   .reduce(
     (stack, it) => {
       stack.push(...it)
       return stack
     },
     []
   )
}
console.timeEnd('push()')
// push(): 1256.3330078125ms
const info = {
  a: [11, 13, 15],
  b: [22, 24, 26],
  c: [33, 35, 37],
}
const a = ['a', 'b', 'c']
const m = 100 * 10000
console.time('concat()')
for (let i = 0; i < m; ++i) {
  a.map(key => info[key])
   .reduce((stack, it) => stack.concat(it))
}
console.timeEnd('concat()')
// concat(): 547.2890625ms
const info = {
  a: [11, 13, 15],
  b: [22, 24, 26],
  c: [33, 35, 37],
}
const a = ['a', 'b', 'c']
const m = 100 * 10000
console.time('push() + ,')
for (let i = 0; i < m; ++i) {
  a.map(key => info[key])
   .reduce((stack, it) => (stack.push(...it), stack))
}
console.timeEnd('push() + ,')
// push() + ,: 1147.3388671875ms
const info = {
  a: [11, 13, 15],
  b: [22, 24, 26],
  c: [33, 35, 37],
}
const a = ['a', 'b', 'c']
const m = 100 * 10000
console.time('flatMap')
for (let i = 0; i < m; ++i) {
  a.flatMap(key => info[key])
}
console.timeEnd('flatMap')
// flatMap: 3049.98095703125ms

結果

  • 構文としては flatMap が一番スマートですが、速度では concat() による reduce が優る模様。
優勝
const info = {
  a: [11, 13, 15],
  b: [22, 24, 26],
  c: [33, 35, 37],
}
const a = ['a', 'b', 'c']

a.map(key => info[key])
 .reduce((stack, it) => stack.concat(it))
  • さらに、コンマ演算子は reduce に渡す関数の構成で速度を僅かながら上げてくれる事もわかりました。

  • 高階関数を使うのは必須として、さらに速い実装があれば教えて下さい!
    (・ω・)< for が速いのは存じております故

StewEucen
「Stew Eucen」「悉生 游漩」は「しちゅう ゆうせん」と読みます。新しい JavaScript フロントエンドフレームワーク x-ninja の中の人です。
http://x-ninja.org
ユーザー登録して、Qiitaをもっと便利に使ってみませんか。
  1. あなたにマッチした記事をお届けします
    ユーザーやタグをフォローすることで、あなたが興味を持つ技術分野の情報をまとめてキャッチアップできます
  2. 便利な情報をあとで効率的に読み返せます
    気に入った記事を「ストック」することで、あとからすぐに検索できます
コメント
この記事にコメントはありません。
あなたもコメントしてみませんか :)
すでにアカウントを持っている方は
ユーザーは見つかりませんでした