Action Script 3.0 では配列管理のトップレベルクラスとして Arrayクラス が知られています。
この Arrayクラス、インデックス(添え字)を真面目に0から振らなくても配列として機能する、C言語からの移民からすれば、なんとも便利で不可解な動作をするのですが、仕組みがわかればソレほど難しくもありません。
種を明かせば、インデックスは文字列で管理され、その実情は連想記憶配列と言ってもいい仕組みなのです。
そんな仕組みですから速度にも限界があり、それを解決する為に Flash10 以降では Vectorクラス が導入されました。
ここでは Vectorクラス については説明しません。各自「as3 Vector」等のキーワードで検索してみてください。
まぁ普通の使い方をしていれば、何らかの整数値とデータを対にするのが一般的かと思います。
この例のように大きなインデックスをしようした場合のメソッドへの影響を検証してみました。
この Arrayクラス、インデックス(添え字)を真面目に0から振らなくても配列として機能する、C言語からの移民からすれば、なんとも便利で不可解な動作をするのですが、仕組みがわかればソレほど難しくもありません。
種を明かせば、インデックスは文字列で管理され、その実情は連想記憶配列と言ってもいい仕組みなのです。
そんな仕組みですから速度にも限界があり、それを解決する為に Flash10 以降では Vectorクラス が導入されました。
ここでは Vectorクラス については説明しません。各自「as3 Vector」等のキーワードで検索してみてください。
柔軟な Array インデックス
インデックスにどんな数値を指定しても、結局(ある程度は正規化されている)文字列になる為、 数値とデータを関連付ける事が大変容易になっています。
var test:Array = new Array();
test[100] = "百";
test[123456789] = "大きい";
test[-56.3] = "マイナス";
まぁ普通の使い方をしていれば、何らかの整数値とデータを対にするのが一般的かと思います。
var comments:Array = new Array();
comments[3265478] = "ちょwwwおまwwwwww";
comments[3265479] = "これはないwww";
comments[3255630] = "才能の無駄遣いwww";
Array.sort
検証コード。3つのデータを文字列の長さでソートする単純な物です。
var test:Array = new Array();
test[3265478] = "ちょwwwおまwwwwww";
test[3265479] = "これはないwww";
test[3255630] = "才能の無駄遣いwww";
var st:int = getTimer();
test.sort(function (a:String, b:String):int
{
var av:int = a.length;
var bv:int = b.length;
if ( av > bv ) return -1;
if ( av < bv ) return 1;
return 0;
});
var sp:int = getTimer() - st;
for(var i:* in test)
{
trace("test[" + i + "]=" + test[i]);
}
trace("time = " + sp +"msec.");
たかが3つのデータのソートにしては時間がかかりすぎですね。
試しにデータをこのようにして見ると・・・
test[1] = "ちょwwwおまwwwwww";
test[4] = "これはないwww";
test[5] = "才能の無駄遣いwww";
インデックスの数値の大きさにモロに影響があります。 インデックスにうっかり 20000000 とか大きな値を使うと、とんでもない事になりますね。
また、インデックスに正の整数以外の物(マイナス値、小数点数、完全な文字列、等)を使うと、ソートの対象外になるようです。
ひと工夫
前述の例のように、大きなインデックスを持つデータをソートしたい場合、以下のようにデータ構造を工夫する必要があります。
var test:Array = new Array();
test[0] = { id:3265478, chat:"ちょwwwおまwwwwww" };
test[1] = { id:3265479, chat:"これはないwww" };
test[2] = { id:3255630, chat:"才能の無駄遣いwww" };
var st:int = getTimer();
test.sort(function (a:Object, b:Object):int
{
var av:int = a.chat.length;
var bv:int = b.chat.length;
if ( av > bv ) return -1;
if ( av < bv ) return 1;
return 0;
});
var sp:int = getTimer() - st;
for(var i:* in test)
{
trace("test[" + i + "]={id:" + test[i].id +",chat:" + test[i].chat + "}");
}
trace("time = " + sp +"msec.");
Array.map
こちらも、配列を総なめする上に、演算結果を配列に出来る使いどころにコツが要るメソッドです。こんなコードを書くと・・・
var test:Array = new Array();
test[3265478] = "ちょwwwおまwwwwww";
test[3265479] = "これはないwww";
test[3255630] = "才能の無駄遣いwww";
var m:Array;
var st:int = getTimer();
m = test.map( function(iter:String, index:int, arr:Array):int
{
return iter.length;
});
var sp:int = getTimer() - st;
trace(m);
trace("time = " + sp +"msec.");
[Fault] exception, information=TypeError: Error #1009: Cannot access a property or method of a null object reference.
発生。
念のため「trace(index);」を入れて確認すると、予想通り 0 から始まっています。
これも結局は、Array.sort と同じ処置で対応しないと、とんでもないループ回数になってしまう事でしょう。
その前に、インスタンスが無い要素(null)に対してアクセスするので、上記のようなエラーでまともに動きませんが。
結論
大きな数値を ID とするデータは、ID を直接配列のインデックスにしてはならない。ここで取り上げたメソッド以外にも、これと同じような動作をする物が在るでしょう。 しっかりと「データ構造」「メソッドの動作」を理解している分には問題ありませんが、
そのまま適当にコーディングすると、大変な事になりますよ・・・

コメントする