ActionScript 2.0 で array_count_values

[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。コメントにソースを書いていただくのはとてもありがたいのですが、コード中の不等号「<」をエスケープしてしまって、その行の以降のコードが消えてしまいます。不等号の部分を「アンドエルティーセミコロン」にしていただけると助かるかもです。
いや〜。アルゴリズムって面白いですね〜。(僕はまだまだですが)

Comments:10

disable 08-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"]) // 1

trace(array_count_values (arr)["hello"]); // 3

tera 08-02-05 (火) 16:09

>disable様
早速のコメントありがとうございます。スマートになるもんですねぇ!勉強になります。
僕はプログラミングが未熟なので、お恥ずかしながら多次元配列と連想配列との運用上の利便性の違いがまだまだイメージできないレベルなのですが、なんとか理解できるよう努めてみます。
今後ともよろしくお願いいたします。

追記:
>「1が2個、”hello” が2個、”world” が1個あるよ」ってのが知りたくて…
って僕が書いてたからですねw。それなら連想配列を使う方が便利ですね。
ちょっと今回は「多いものから順に二次元配列に格納する」というのが欲しい形なので、引き続きいじってみます。ありがとうございますー。

むらけん 08-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個あります

匿名 08-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 08-02-05 (火) 18:22

>むらけんさん
ご教授ありがとうございますー。
凄い!!短い!!!
密かに僕の方でもできたので喜んでいたのに、遥かにスマートな感じですね〜。
あとでじっくり調べさせてもらいます。
ありがとうございましたー。

匿名 08-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 08-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 08-02-05 (火) 18:48

>disable様
何度もご丁寧にコメントいただいて本当にありがとうございますー。そしてコードが短い!
勉強させていただく箇所が山盛りです。
このエントリ書いて良かったです。
ありがとうございます。今後ともよろしくお願いいたします。

むらけん 08-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 コメント欄がコードだらけに。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 < 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個あります

tera 08-02-05 (火) 20:19

>むらけんさん
コメントらんのコードはかけちゃってますが(←こっちも直してみました)、エントリ中にペーストさせていただいた分はちゃんと表示されてるので大丈夫だと思いますが、いかがでしょうか?

おふたかたのコードとも、こちらで動かさせていただいてきちんと動いてますー!ありがとうございます。

Comment Form
Remember personal info

Trackbacks:0

Trackback URL for this entry
http://www.trick7.com/blog/2008/02/05-143729.php/trackback
Listed below are links to weblogs that reference
ActionScript 2.0 で array_count_values from trick7
AS3習得本
AS3の全容を学習できる本。この中でどれか1冊自分に合ったものを。
Adobe Flash CS4 詳細!ActionScript3.0入門ノート ActionScript3.0 プロフェッショナルガイド 初めてのActionScript 3.0 Flashユーザーのためのステップアップガイド 詳説 ActionScript 3.0 Actionscript 3.0 Cookbook
AS3発展本
ASでアニメーションさせる面白さを知るための本。
Flash Math & Physics Design:ActionScript 3.0による数学・物理学表現[入門編] ActionScript 3.0 アニメーション AdvancED ActionScript 3.0 Animation (Advanced)
AS2
"Flash"ではなく"ActionScript2.0"学習のための良著。他にもいろいろ読んだけど、この4冊を読んだ後、自分が成長できた感じがしました。
FLASH ActionScript 2.0入門完全ガイド+実践サンプル集 [CD-ROM付] Essential Actionscript 2.0 Flash 8 Essentials Foundation Actionscript Animation: Making Things Move (Foundation)

あわせて読みたいブログパーツ

相互リンク

hi-posiさん
携帯Flashといえばhi-posiの岡田昇三さん。FlashLiteの有益な記事もたくさん書かれていていつもお世話になってます。ついにご挨拶させていただきました。面白すぎる人でしたw。

Return to page top