LoginSignup
17
7

More than 3 years have passed since last update.

Array.includesと Set.has の速度比較をした。

Posted at

Array.includesとSet.hasで速度差がどれぐらい出るかを調べた。
良くあるObjectの添字を使ったテクニック等とも比較。


const { performance } = require('perf_hooks');

const test = (len=100) => {

    const targetLen = Math.floor(len /10)

    const  shuffle = (a) => {
        const c = [...a]
        for (let i = c.length - 1; i > 0; i--) {
            const j = Math.floor(Math.random() * (i + 1));
            [c[i], c[j]] = [c[j], c[i]]
        }
        return c
    }

    const spec = [
        ["nodeのバージョン",process.versions.node],
        ["配列のサイズ" , len ],
        ["検索する項目数" , targetLen ]
    ]


    //配列をlen個作成する [0,1,2,3,4,...,len-1]
    const base = Array.from({length: len}, (v, k) => k)

    //シャッフルする
    const ary = shuffle(base)

    //Set化する
    const set =(() => {
        const start = performance.now()
        const set = new Set(ary)
        const end =  performance.now()
        spec.push([ "Setの生成時間" , end - start])
        return set
    })()

    //Mapの生成
    const map = (() => {
        const pre = base.map(b => [b,b])
        const start = performance.now()
        const map = new Map(pre)
        const end = performance.now()
        spec.push([ "Mapの生成時間" , end - start ])
        return map
    })()

    //数字を添え字にしたオブジェクトを作る {"0":0,"1":1,...,[len-1]:len-1}
    const obj = (() => {
        const start = performance.now()
        const obj = ary.reduce((pre,cur) => {
            pre[`${cur}`] = cur
            return pre
        }, {})

        const end = performance.now()
        spec.push([ "Objectの生成時間" , end - start ])

        return obj
    })() 



console.log(`

${spec.map(r => r.join("|")).join("\n")}

`)


    //存在チェックの試験用の配列
    const target = shuffle(base).slice(0,targetLen)

    const result = [
        ["含むチェックの方式","処理時間時間"],
    ]



    //indexOf を使う
    {
        const start = performance.now();
        for(let t of target ){
            if(ary.indexOf(t) > -1){

            }
        }
        const end = performance.now();

        result.push([ "Array.indexOf" , end - start])
    }


    //Array.inclueds のテスト
    {
        const start = performance.now();
        for(let t of target ){
            if(ary.includes(t)){

            }
        }
        const end = performance.now();

        result.push([ "Array.inclueds" , end - start])
    }

    //Set.has のテスト
    {
        const start = performance.now();
        for(let t of target ){
            if(set.has(t)){

            }
        }
        const end = performance.now();    
        result.push([ "Set.has" , end - start])
    }


    //Map.has のテスト
    {
        const start = performance.now();
        for(let t of target ){
            if(map.has(t)){

            }
        }
        const end = performance.now();    
        result.push([ "Map.has" , end - start])
    }


    //オブジェクトの key を使ったテクニック のテスト

    {
        const start = performance.now();
        for(let t of target ){
            if(obj[t]){

            }
        }
        const end = performance.now();    
        result.push([ "obj[t]" , end - start])
    }


    // in でも試してみる

    {

        const start = performance.now();
        for(let t of target ){
            if( t in obj){

            }
        }
        const end = performance.now();    
        result.push([ "t in obj" , end - start])

    }


console.log(`

${result.map(r => r.join("|")).join("\n")}

`)



}

test(100000)

1回目

項目
nodeのバージョン 12.18.1
配列のサイズ 100000
検索する項目数 10000
Setの生成時間 8.558184027671814
Mapの生成時間 13.922562003135681
Objectの生成時間 31.00487995147705
チェックの方式 処理時間時間
Array.indexOf 944.757071018219
Array.inclueds 944.7714960575104
Set.has 2.41020405292511
Map.has 2.5640859603881836
obj[t] 1.2104129791259766
t in obj 0.7970190048217773

2回目

項目
nodeのバージョン 12.18.1
配列のサイズ 100000
検索する項目数 10000
Setの生成時間 8.59699296951294
Mapの生成時間 11.606724977493286
Objectの生成時間 35.41410505771637
チェックの方式 処理時間時間
Array.indexOf 945.146420955658
Array.inclueds 945.0419319868088
Set.has 2.4140039682388306
Map.has 2.5660550594329834
obj[t] 1.2223680019378662
t in obj 0.8045949935913086

3回目

項目
nodeのバージョン 12.18.1
配列のサイズ 100000
検索する項目数 10000
Setの生成時間 8.761895060539246
Mapの生成時間 11.589484095573425
Objectの生成時間 30.759024024009705
チェックの方式 処理時間時間
Array.indexOf 943.3850150108337
Array.inclueds 947.2091970443726
Set.has 2.461833953857422
Map.has 2.6097559928894043
obj[t] 1.2358649969100952
t in obj 0.8159409761428833

結論 Setを使う。

結果的だけみると in 演算子を使うパターンが一番早いが object に一旦変換するテクニックは
生成コストが高く常に使って効果を得られるようなテクニックではないので使わないほうが良い。

また、存在チェックしたい物が stringやnumber以外の場合は使えない。

Setは生成コストはそれほど高くなく、検索も早いので、状況によっては含むチェックのためだけに 配列から一旦Setを生成する価値はありそう。

Set.has と Map.hasはスピードにあまり差が無い。(MapがSetに依存してるのかな?

indexof と includes は速度に差は無く順当に遅い

あまり不思議な点はなかった。

ちなみに Map の key が オブジェクトでも良いって最近知った。

17
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
7