1
0

More than 1 year has passed since last update.

indexOfをforするのはよくない

Last updated at Posted at 2021-09-28

WebGL用に自前の関数で4Mb程度のobj読み込みをした
ポリゴン命令の頂点の重複除去をしたあと
index bufferの生成にindexOfを
全ポリゴン命令約21万に対して回していたら43秒掛かった
なんだこれは

indexOf

どちらも検索開始位置を第二引数に指定できる
そこから配列の中を一つづつ検索していく
これは目的の要素を配列の最後に置いて二つを走らせることでわかる

一つだけのインデックスを調べたいのならこれでも十分だが
全要素に対して検索をすると膨大な時間がかかる

並べ替えや重複除去の操作をした後に
全要素の位置を配列に記録する等の用途であれば
先に辞書を作った方が良いことは明らか

Map

new Map()はObject.fromEntries()のように引数に[[key,value]...]を渡すことでMapを作ることができる
今回はkeyに値を持ってvalueにインデックスを持たせたいがこれは.map()で簡単に作れる

new Map(array.map((x,i)=>[x,i]));

このMapにインデックスが欲しい値を渡すと値が最後に登場するインデックスを取得できる
最初のインデックスが欲しければ

new Map(array.reverse().map((x,i)=>[x,i]));

※追記(2022/1/15)
書いていて多少不安は残るがmapの中の関数はArrayコンストラクタでも動く
Entriesは一番目と二番目の要素のみ保証されていれば良いらしい
つまり

new Map(array.map(Array));

短いね

速い

重複のある配列Aから重複を除去した配列Bの対応を明確にする目的で
Aと同じ長さのBのインデックスの羅列Cを取得する
Aの長さは208353 Bの長さは34834 である

indexOf
C=A.map(x=>B.indexOf(x));
Map
const map=new Map(B.map((x,i)=>[x,i]));
C=A.map(x=>map.get(x));

indexOfを使ったコードは43秒ほど掛かったが
Mapを使ったコードでは300ms周辺で済んだ
Mapの代わりにObjectも使ってみたが平均して20msほどObjectの方が遅かった

indexOfをforするなら先に辞書を作ろう

1
0
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
1
0