感嘆した話。 ―配列への循環アクセス―

ある配列があって、それに循環的にアクセスする必要に迫られることはままあります。
この処理に関して、最近知った書き方があったのでメモメモ。
タイトルのような呼び方をするのかどうかは不明ですが…。


例えば、こう。
幹音だけの音名の配列、naturalToneがあります。
これに、
・順番に
・1秒ごとに
・永遠に
アクセスしたいとします。
ラシドレミファソラシドレミファソ…という具合です。
例としてはイマイチですが><
ここでは、JavaScriptを使います。(Firebugにconsole.logします。)


つい最近まで、自分は

var naturalTone = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
var naturalToneLength = naturalTone.length;
var currentIndex = 0;
var span = 1000;

var roop = setInterval(function(){
	console.log(naturalTone[currentIndex++]);
	if(currentIndex >= naturalToneLength) {
		currentIndex = 0;
	}
}, span);

という書き方しか知りませんでした。
確かに、if文のあたりになんとなくスッキリしないものは感じていたのですが…。


で、新しく知った書き方。(roop部分を抜粋です。)

var roop = setInterval(function() {
	console.log(naturalTone[currentIndex++]);
	currentIndex = currentIndex % naturalToneLength;
}, span);

行数はあんまり変わらないですが、内容が全然違いますね。
長くスクリプターをしてましたが、自分はこの方法を知って、まさに「目からウロコ」でした。
「そんなもん常識だよ。」と思われた方も多いでしょうか><


今回は1秒ごとの処理でしたが、回数を決めたfor文で
・毎回インクリメントと条件判定、{配列の長さ}回に一回0を代入
・毎回インクリメントと余りの再代入
の処理を比べた時にどちらが速く、メモリに優しいか、近いうちに調べてみます。
[追記] テストしてみた。 [/追記]
余りを出すときにプリインクリメントするのもアリですね。


どの演算子をどう組み合わせたらどのようにメモリが使われるか。
基本的なところが勉強不足です><



余談です。
もっと短く

var roop = setInterval(function() {
	console.log(naturalTone[currentIndex++ % naturalToneLength]);
}, span);

でも同じ出力になりますが、これだといつかはcurrentIndexがNumber.MAX_VALUEに達してしまいます。