- 2008-02-05 (火)
- action script
[1, "hello", 1, "world", "hello"] という配列があった時に、配列内の重複する要素の個数をカウントして、「1が2個、"hello" が2個、"world" が1個あるよ」ってのが知りたくて、調べてみたところ php の array-count-values 関数が該当することが分かりました。ActionScript2.0 では同様の関数が見当たらなかったので、似たようなのを作りました。php のソースコードの見方が分からなかったので、アルゴリズムも自力なのが不安ですが一応動いているので、誰かが添削してくれるのをうっすら期待しつつ一応公開しておきます。
追記:
いろいろご教授いただきまして、コメント欄だとコードの表示が崩れるので本文エントリに追記していきますね。ありがとうございます。
頂いたコードは全て Flash のフレームにコピペするだけで動くので、試しに動かしてみて皆さんのコードのスマートさを味わってみてください!
フレームスクリプトとして記述するタイプのごく普通の関数です。
function array_count_values(arr:Array):Array{ //並べ替えて[1,1,"hello","hello","hello","world"]にソート arr.sort(); //返り値となる2次元配列を作成。2次元目の1番目の要素を入れておく var returnArr:Array = new Array([arr[0],1]); //ループ内で使う番号 var num:Number = 0; for(var i:Number = 1; i<arr.length; i++){ //前の要素と違う要素だった時、配列を作成し、2次元配列の要素として追加する if(arr[i]!=arr[i-1]){ returnArr.push(new Array(arr[i],0)); num++; } returnArr[num][1]+=1; } trace(returnArr[0][0]+"は"+returnArr[0][1]+"個あります"); //出力例「1は2個あります」 return returnArr; } //使い方 var arr:Array = [1, "hello", 1, "world", "hello", "hello"]; array_count_values(arr);
返り値は2次元配列です。[[1,2],["hello",3],["world",1]] みたいな感じです。
さらにここから、array_count_values 関数の第2パラメーターに Boolean 設定して true なら「個数の多いものからソート」して [["hello",3],[1,2],["world",1]] に並べ替える機能を付けたいのだけど、2次元目の要素内容をキーにして1次元目の要素を sortOn することができるのかが分からない。
パッと思いつかないので今回は力技でなんとか乗り切ることにします。。一応実装したので、バージョン2として下に追記しておきました。
修正バージョン
降順、昇順にソートできるようにしました。第2パラメーターで「不等号の文字(<, >)」で指定するというアナログな指定方法ですw。バブルソートというアルゴリズムを使ってみました。
function array_count_values(_array:Array,sort:String):Array{ _array.sort(); //返り値となる2次元配列を作成。2次元目の1番目の要素を入れておく var returnArr:Array = new Array([_array[0],1]); //ループ内で使う番号 var num:Number = 0; for(var i:Number = 1; i<_array.length; i++){ //前の要素と違う要素だった時、配列を作成し、2次元配列の要素として追加する if(_array[i]!=_array[i-1]){ returnArr.push(new Array(_array[i],0)); num++; } returnArr[num][1]+=1; } if(sort){ //バブルソート var tmp:Array = new Array(); for (var i:Number = 0;i < returnArr.length - 1;i++) { for (var j:Number = 0;j < returnArr.length - 1;j++) { if(sort=="<"){ //昇順 if (returnArr[j + 1][1] < returnArr[j][1]) { tmp = returnArr[j]; returnArr[j] = returnArr[j + 1]; returnArr[j + 1] = tmp; } }else{ //降順 if (returnArr[j + 1][1] > returnArr[j][1]) { tmp = returnArr[j]; returnArr[j] = returnArr[j + 1]; returnArr[j + 1] = tmp; } } } } } return returnArr; } //使い方 var arr:Array = ["hello", "world", "hello", "hello","oops","world","hello", "world", "world","hoge","hoge"]; trace(array_count_values(arr,"<")) //出力例:昇順(左が小さい順に並ぶ) trace(array_count_values(arr,">")) //出力例:降順(右が小さい順に並ぶ) trace(array_count_values(arr)) //出力例:ソート無し(ただし sort() はかかっている)
disable様バージョン
戻り値を連想配列にしてみるのはどうでしょうか?
function array_count_values (_array:Array):Object {
var _obj:Object = new Object ();
for (var i:Number = 0; i < _array.length; i++){
_obj[_array[i]] = (_obj[_array[i]] == null) ? 1 : _obj[_array[i]] + 1;
}
return _obj;
}
//使い方
var arr:Array = [1, "hello", 1, "world", "hello", "hello"];
var obj:Object = array_count_values (arr); //連想配列
trace(obj["world"]) // 1
trace(array_count_values (arr)["hello"]); // 3
むらけんさんバージョン
teraさんの求める形だとこうなるでしょうか。2loopしてしまいますが。。
僕なら最後のループは消して、{value:hello,cnt:2}というObjectの入った配列を返しますかね。
function array_count_values(arr:Array,is_sort:Boolean):Array {
var sort_array:Array = new Array();
var fix_array:Array = new Array();
var _obj:Object = new Object();
for (var i:Number = 0, len:Number = arr.length; i < len; i++) {
if (_obj[arr[i]] == undefined) {
_obj[arr[i]] = {value:arr[i],cnt:1};
sort_array.push(_obj[arr[i]]);
}else{
_obj[arr[i]].cnt++;
}
}
if (is_sort)sort_array.sortOn("cnt", Array.DESCENDING | Array.NUMERIC);
for (var j:Number = 0, len:Number = sort_array.length; j < len; j++)fix_array.push([sort_array[j].value, sort_array[j].cnt]);
return fix_array;
}
var arr:Array = [1, "hello", 1, "world", "hello", "hello"];
var returnArr:Array = array_count_values(arr,true);
trace(returnArr[0][0]+"は"+returnArr[0][1]+"個あります"); //helloは3個あります
var returnArr:Array = array_count_values(arr);
trace(returnArr[0][0]+"は"+returnArr[0][1]+"個あります"); //1は2個あります
disable様バージョン2
あまり理解していず、申し訳ありません・・・
ちょっといじってみました。
と思ったら、むらけんさんからもっ
function array_count_values (_array:Array, _sortFlg:Boolean):Array {
var _a:Array = new Array ();
var _obj:Object = new Object ();
for (var i:Number = 0; i < _array.length; i++) {
_obj[_array[i]] = (_obj[_array[i]] == null) ? 1 : _obj[_array[i]] +1;
}
for(var _prop:String in _obj){;
_a.push ({name:_prop, value:_obj[_prop]});
}
if(_sortFlg) _a.sortOn ("value",Array.NUMERIC | Array.DESCENDING);
return _a;
}
//使い方
var arr:Array = [1, "hello", 1, "world", "hello", "hello"];
trace(array_count_values (arr,true)[0].name); //1番多い名前
trace(array_count_values (arr,true)[0].value); //1番多い名前の数
trace(array_count_values (arr,true)[1].name); //2番目に多い名前
trace(array_count_values (arr,true)[1].value); //2番目に多い名前の数
スマートかどうかは・・・(←スマートです! by tera)
一応お知らせ
「どう書く?.org」みたいになってきましたねw。コメントにソースを書いていただくのはとてもありがたいのですが、コード中の不等号「<」をエスケープしてしまって、その行の以降のコードが消えてしまいます。不等号の部分を「アンドエルティーセミコロン」にしていただけると助かるかもです。
いや〜。アルゴリズムって面白いですね〜。(僕はまだまだですが)
Comment:10
- disable 2008-02-05 (火) 15:39
-
戻り値を連想配列にしてみるのはどうでしょうか?
function array_count_values (_array:Array):Object {
var _obj:Object = new Object ();
for (var i:Number = 0; i < _array.length; i++){
_obj[_array[i]] = (_obj[_array[i]] == null) ? 1 : _obj[_array[i]] + 1;
}
return _obj;}
//使い方
var arr:Array = [1, "hello", 1, "world", "hello", "hello"];var obj:Object = array_count_values (arr); //連想配列
trace(obj["world"]) // 1trace(array_count_values (arr)["hello"]); // 3
- tera 2008-02-05 (火) 16:09
-
>disable様
早速のコメントありがとうございます。スマートになるもんですねぇ!勉強になります。
僕はプログラミングが未熟なので、お恥ずかしながら多次元配列と連想配列との運用上の利便性の違いがまだまだイメージできないレベルなのですが、なんとか理解できるよう努めてみます。
今後ともよろしくお願いいたします。追記:
>「1が2個、"hello" が2個、"world" が1個あるよ」ってのが知りたくて…
って僕が書いてたからですねw。それなら連想配列を使う方が便利ですね。
ちょっと今回は「多いものから順に二次元配列に格納する」というのが欲しい形なので、引き続きいじってみます。ありがとうございますー。 - むらけん 2008-02-05 (火) 17:27
-
teraさんの求める形だとこうなるでしょうか。
2loopしてしまいますが。。僕なら最後のループは消して、{value:hello,cnt:2}というObjectの入った配列を返しますかね。
function array_count_values(arr:Array,is_sort:Boolean):Array {
var sort_array:Array = new Array();
var fix_array:Array = new Array();
var _obj:Object = new Object();
for (var i:Number = 0, len:Number = arr.length; i < len; i++) {
if (_obj[arr[i]] == undefined) {
_obj[arr[i]] = {value:arr[i],cnt:1};
sort_array.push(_obj[arr[i]]);
}else{
_obj[arr[i]].cnt++;
}
}
if (is_sort)sort_array.sortOn("cnt", Array.DESCENDING | Array.NUMERIC);
for (var j:Number = 0, len:Number = sort_array.length; j < len; j++)fix_array.push([sort_array[j].value, sort_array[j].cnt]);
return fix_array;
}var arr:Array = [1, "hello", 1, "world", "hello", "hello"];
var returnArr:Array = array_count_values(arr,true);
trace(returnArr[0][0]+"は"+returnArr[0][1]+"個あります"); //helloは3個ありますvar returnArr:Array = array_count_values(arr);
trace(returnArr[0][0]+"は"+returnArr[0][1]+"個あります"); //1は2個あります - No Name 2008-02-05 (火) 18:09
-
あまり理解していず、申し訳ありません・・・
ちょっといじってみました。
と思ったら、むらけんさんからもっfunction array_count_values (_array:Array):Array {
var _a:Array = new Array ();
var _obj:Object = new Object ();for (var i:Number = 0; i
_obj[_array[i]] = (_obj[_array[i]] == null) ? 1 : _obj[_array[i]] + 1;
}
for(var _prop:String in _obj){;_a.push ({name:_prop, value:_obj[_prop]});
_a.sortOn ("value",Array.NUMERIC | Array.DESCENDING);}
return _a;}
//使い方
var arr:Array = [1, "hello", 1, "world", "hello", "hello"];trace(array_count_values (arr)[0].name); //1番多い名前
trace(array_count_values (arr)[0].value); //1番多い名前の数trace(array_count_values (arr)[1].name); //2番目に多い名前
trace(array_count_values (arr)[1].value); //2番目に多い名前の数スマートかどうかは・・・
- tera 2008-02-05 (火) 18:22
-
>むらけんさん
ご教授ありがとうございますー。
凄い!!短い!!!
密かに僕の方でもできたので喜んでいたのに、遥かにスマートな感じですね〜。
あとでじっくり調べさせてもらいます。
ありがとうございましたー。 - No Name 2008-02-05 (火) 18:23
-
フラグの有無入れてなかったです。。。
先程の投稿は忘れていただき、こちらを。。。不等号も直しておきました!
function array_count_values (_array:Array, _sortFlg:Boolean):Array {
var _a:Array = new Array ();
var _obj:Object = new Object ();for (var i:Number = 0; i < _array.length; i++) {
_obj[_array[i]] = (_obj[_array[i]] == null) ? 1 : _obj[_array[i]] + 1;
}
for(var _prop:String in _obj){;_a.push ({name:_prop, value:_obj[_prop]});
if(_sortFlg) _a.sortOn ("value",Array.NUMERIC | Array.DESCENDING);}
return _a;}
//使い方
var arr:Array = [1, "hello", 1, "world", "hello", "hello"];trace(array_count_values (arr,true)[0].name); //1番多い名前
trace(array_count_values (arr,true)[0].value); //1番多い名前の数trace(array_count_values (arr,true)[1].name); //2番目に多い名前
trace(array_count_values (arr,true)[1].value); //2番目に多い名前の数
- disable 2008-02-05 (火) 18:24
-
間違いだらけでテンパってまいりました!
こっちですね。。。function array_count_values (_array:Array, _sortFlg:Boolean):Array {
var _a:Array = new Array ();
var _obj:Object = new Object ();for (var i:Number = 0; i < _array.length; i++) {
_obj[_array[i]] = (_obj[_array[i]] == null) ? 1 : _obj[_array[i]] + 1;
}
for(var _prop:String in _obj){;_a.push ({name:_prop, value:_obj[_prop]});
}
if(_sortFlg) _a.sortOn ("value",Array.NUMERIC | Array.DESCENDING);
return _a;}
//使い方
var arr:Array = [1, "hello", 1, "world", "hello", "hello"];trace(array_count_values (arr,true)[0].name); //1番多い名前
trace(array_count_values (arr,true)[0].value); //1番多い名前の数trace(array_count_values (arr,true)[1].name); //2番目に多い名前
trace(array_count_values (arr,true)[1].value); //2番目に多い名前の数
- tera 2008-02-05 (火) 18:48
-
>disable様
何度もご丁寧にコメントいただいて本当にありがとうございますー。そしてコードが短い!
勉強させていただく箇所が山盛りです。
このエントリ書いて良かったです。
ありがとうございます。今後ともよろしくお願いいたします。 - むらけん 2008-02-05 (火) 19:55
-
コメント欄がコードだらけに。w
なぜかソースが欠けてしまっているので、もう一度張ってみます。function array_count_values(arr:Array,is_sort:Boolean):Array {
var sort_array:Array = new Array();
var fix_array:Array = new Array();
var _obj:Object = new Object();
for (var i:Number = 0, len:Number = arr.length; i if (_obj[arr[i]] == undefined) {
_obj[arr[i]] = {value:arr[i],cnt:1};
sort_array.push(_obj[arr[i]]);
}else
_obj[arr[i]].cnt++;
}
if (is_sort)sort_array.sortOn("cnt", Array.DESCENDING | Array.NUMERIC);
for (var j:Number = 0, len:Number = sort_array.length; j return fix_array;
}var arr:Array = [1, "hello", 1, "world", "hello", "hello"];
var returnArr:Array = array_count_values(arr,true);
trace(returnArr[0][0]+"は"+returnArr[0][1]+"個あります"); //helloは3個ありますvar returnArr:Array = array_count_values(arr);
trace(returnArr[0][0]+"は"+returnArr[0][1]+"個あります"); //1は2個あります - tera 2008-02-05 (火) 20:19
-
>むらけんさん
コメントらんのコードはかけちゃってますが(←こっちも直してみました)、エントリ中にペーストさせていただいた分はちゃんと表示されてるので大丈夫だと思いますが、いかがでしょうか?おふたかたのコードとも、こちらで動かさせていただいてきちんと動いてますー!ありがとうございます。
Trackback:0
- TrackBack URL for this entry
- http://www.trick7.com/blog/mt-tb.cgi/681
- Listed below are links to weblogs that reference
- ActionScript 2.0 で array_count_values from trick7.com blog




