連想配列のソート

JavaScriptでは可変index番号をキーにもつ普通の配列はソートできますが、連想配列はソートできません。 また、連想配列の場合は配列の長さもlengthで取る事はできません。

普通の配列番号をindexとする配列と子オブジェクトの別の配列を作るか、 最初から配列&オブジェクトの組み合わせも作っておけば、長さもわかりますしソートも自由にできるようになります。
必要に応じて最初から準備しておく方が良い場合もあります。
(Operaは条件次第で、この方法でも正しくソートができません)

自分であれこれ書くのが面倒な方 =>>> 連想配列の操作用関数

詳 細


var aTest = new Array();
aTest['ccc'] = 8;
aTest['aaa'] = 4;
aTest['ddd'] = 9;
aTest['bbb'] = 4;
aTest['eee'] = 1;

/*または オブジェクトとして */
var aTest = {'aaa':4,'bbb':4,'ccc':8,'ddd':9,'eee':1}
こういう単純な連想配列(オブジェクト)を作ってしまった場合は、長さも(固定指定していなければ)lengthプロパティですぐ取れないし、 lengthをnew Array(5)と設定しても、『length』と言うキーを作ると配列のlengthは無効になるし、、、JavaScriptの配列は自動で長さが変ってくれるし・・・ と言う事で、このままでは並べ替えや長さを取る事ができません。

/* 長さを取るだけ */
var i = 0;
for( key in aTest ){ i++; } /* keyと言う文字は任意の変数名 */
alert(i)

長さを取るだけなら for(i in 配列)文を使って繰り返し回数を数えるだけですね。 このfor()文の中では keyがキー、aTest[key]がvalueですので、色々条件も付けて調べたりもできます。


/* ソートする準備 新配列作成*/
var aSIN = new Array();
for( var i in aTest ){
    aSIN.push({key:i,val:aTest[i]});
}

/* 別の書き方をすれば */
var aSIN = new Array();
var t = 0;
for( var i in aTest ){
    aSIN[t] = new Object(); //new Array()でもほぼ同じ
    sSIN[t].key = i;
    aSIN[t].val = aTest[i]
    t++;
}
新しい配列番号indexをキーに持つ普通の配列を親として作り、その1つ1つの要素を更に連想配列にして 今までのaTestのキーとバリューを連想配列の値とした2次元配列にします。

これで、aSIN[番号]として現在の並び順の情報も持っていますし、長さlengthプロパティもaSINが持っています。
元配列aTestのキーはaSIN[番号]['key'] または aSIN[番号].key として簡単に参照でき、 値はaSIN[番号]['val'] または aSIN[番号].val として参照できる状態の別配列ができます。
元の配列aTestもゴミではなく、キーから値を参照できる配列として役に立ちます。

初心者向けに図解すると aTestは下の表の状態。
indexも無くキーで値を照会するのみ。
キー
ccc8
aaa4
ddd9
bbb4
eee1
aSINはこの状態
indexキー
1keyccc
val8
2keyaaa
val4
3keyddd
val9
4keybbb
val4
5keyeee
val1
indexはソートなどによって可変


/* 配列の長さ */
alert( aSIN.length )


/* 配列全体を処理たい場合 (例:並び順をチェック) */
for(i=0; i<aSIN.length; i++){
   alert(aSIN[i].key + ' = ' + aSIN[i].val + '\n' )
}


/* キー ソート (キーが小さい順) */
aSIN.sort(smallKey);
function smallKey(a,b){ return (a.key > b.key) ? 1 : -1 ; }



/* キー ソート (キーが大きい順) */
aSIN.sort(largeKey);
function largeKey(a,b){ return (a.key < b.key) ? 1 : -1 ; }



/* バリュー ソート (値が小さい順) */
aSIN.sort(smallVal);
function smallVal(a,b){ return (a.val > b.val) ? 1 : -1 ; }



/* バリュー ソート (値が大きい順) */
aSIN.sort(largeVal);
function largeVal(a,b){ return (a.val < b.val) ? 1 : -1 ; }



ソート関数は2つの値を順に引き出して比較して並べ替えますから、 参照する値をaSINではなく、引き出したaSINのkeyやvalとすれば簡単に比較ができます。
これでaTestとaSINがあれば、『キーからの参照』『長さ』『並べ替え』ができる使いやすい状態になります。

必要に応じて処理後に元の配列の形態(キー&バリューのペア)に戻す場合は

var bTest = new Array();
for( var i=0; i < aSIN.length; i++ ){
bTest[aSIN[i].key] = aSIN[i].val; }

直前のソートボタンのどれを押したかによって元の状態に戻した配列の並び順が変ってきます。 ただし間違えないで欲しいのが、並び順が変っただけであってキーとのペアは当然同じままです。 また並び順が変ったとは言え、連想配列の状態にはindexがないので『何番目』と言う取り出しはできません。 処理の都合上や表示の都合上の為に並び順を変えてるに過ぎないと言う事です。

商品リスト等の場合はユニークである商品番号を配列のキーにしてしまう場合がありますが、 配列は長さを返す時に空要素の物も含めて一番大きいインデックス番号+1を返してきます。
また、配列(Array)で作成してしまうと、思わぬ落とし穴(数値キーはindexとして扱われる)があります。 商品番号をキーにする場合は必ず new Object()か ary = {} という形で初期オブジェクトを作ってください。 new Array()や ary = [] では作成しないように。
同時に配列の作成時に普通のインデックスを持つ配列を親にしたソート用配列も作っておけば、 あとからfor()文を回して余計な手間をかけるよりも便利です。

後日情報として:
Operaはnew Object()や {}で作成した明らかにオブジェクトであっても、 数値キーが混じっていると、並び順は数値キーが先頭に来るようになっています。 従って、一旦可変indexタイプにしてソートして戻しても、、数値キー以外の部分は これまで書いてきた方法でソートされますが、まず数値キーが先頭に来て、、、、という ソートが役に立たない仕様になっています。 従って少数派とは言え、数字キーが混じってるオブジェクトはソートが完璧にできない可能性がある事だけは念頭に入れてプログラムしないといけないでしょう。

キーの付け方のまとめは
配列ソートの最下部にあります。


専用ページから申し込むと
So-netより高い3万円CB

案ずるより産むが易し
使ってみれば疑問も解決

XREA+ (plus) 206円/月
( お試し7日間 )

CORE SERVER 428円/月
( お試し15日間 )

ロリポップ 270円/月
( お試し期間10日間 )

ヘテムル 1620円/月
( お試し期間15日間 )

さくら 129円/月
( お試し期間2週間 )

無駄な高額ドメイン管理料金払ってませんか?

バリュードメイン
ムームードメイン