- ベストアンサー
Action Script 2.0 配列の比較
- 複数のチェックボックスの値を取得し、配列に格納する方法について教えてください。
- 複数のチェックボックスがあり、値の取得はできているが、配列の比較方法についてわからないです。
- チェックボックスの値を配列に入れた後、一致項目の多い配列を選択する方法について教えてください。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
#2です。 勘違いしていた部分がありましたので、スクリプトを訂正いたします。 FlashPlayer 8 以上で動作します。 (↓ 各行頭に全角のスペースが入っています。コピーする際は、全て半角のスペースかタブに置き換えてください) //*** /* 初期設定 */ //チェックボックスの選択状況を格納する配列 var check_status:Array = new Array(); //チェックパターンデータ //最後の要素はパターン名 var check_ptt:Array = [ [ 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , "サンプルA" ] , [ 1 , 0 , 0 , 1 , 0 , 1 , 0 , 0 , "サンプルB" ] , [ 0 , 1 , 1 , 0 , 1 , 1 , 1 , 1 , "サンプルC" ] ]; //評価を格納する配列 var score_tbl:Array = new Array(); //チェックボックスの総数 var box_max:Number = 8; //チェックボックスが配置されているタイムラインを保持 var box_line:MovieClip = this; /* 照合の処理 */ function Check_Compare():Void { var i:Number , j:Number; var score:Number , check_score:Number; var flags:Number; //選択状況とパターンを総当たりで照合する for( i = 0 ; i < check_ptt.length ; i++ ) { //評価をリセット score = 0; check_score = 0; for( j = 0 ; j < box_max ; j++ ) { //選択されるべき項目との一致を照合 //両方とも1(選択されている)である場合、評価が+1、それ以外は加算されない check_score += check_ptt[ i ][ j ] & check_status[ j ]; //全体の照合処理 //一致していた場合、評価が+1、それ以外は加算されない score += Number( check_ptt[ i ][ j ] == check_status[ j ] ); } //デバッグ trace( "Score " + i + " = " + score ); trace( "Check_on " + i + " = " + check_score ); //評価を記録する配列変数に結果を記録 //フィールド名 // ptt_no:パターンの番号 // check_on:選択するべき項目と一致した数 // total_score:総合評価 score_tbl[ i ] = { ptt_no : i , check_on : check_score , total_score : score }; } //評価の高い順に並べ替え //選択するべき項目と一致した数が多いものほど高評価 //同点の場合は総合評価で優劣を決める flags = Array.NUMERIC | Array.DESCENDING; score_tbl.sortOn( [ "check_on" , "total_score" ] , [ flags , flags ] ); /*ここに、評価を利用する処理を書く*/ /*今回は一致した数が最も多かったパターンの名前を出力*/ trace( "一致数の高いパターンは " + check_ptt[ score_tbl[ 0 ].ptt_no ][ box_max ] ); } /* 照合開始ボタンの処理 */ btn.onRelease = function():Void { var i:Number; //選択状況を配列変数に格納 //選択されている場合1、されていない場合は0を入れる for( i = 0 ; i < box_max ; i++ ) { check_status[ i ] = Number( box_line[ "cbox" + i ].selected ); } //パターンと照合する Check_Compare(); }; //*** 主な変更点ですが。 まず、パターンのデータが単調で結果を検証しにくかったので、変更しました。 選択するべき項目を選択した数が同数だった場合、選択するべきではない項目と一致している数が多いものほど評価が高くなることを検証しやすくしています。 同時に出力される、Score と Check_on の値に注目してください。 Check_on は、選択するべき項目が一致している数です。 Check_on が同点の場合は、選択するべきではない項目も含めた全体の一致数である Score が高い方が高い評価になります。 評価を配列変数に残し、関数外でも利用できるようにしました。 配列変数 score_tbl の各要素に仕切り(フィールド)を作り、複数の情報をまとめて管理しています。 フィールドの名前と内容は、スクリプト内のコメントをご参考になさってください。 並べ替えの結果、score_tbl[ 0 ] が最も評価の高いパターンの情報になります。 なお、この並べ替えを行うにあたり、FlashPlayer 8 から追加された、フィールドごとの条件を指定するソートを利用しています。 ソートの内容は、フィールド名”check_on”について降順で並べ替え、同点だった場合はフィールド名”total_score”に注目し、total_score の高い方が上位にくるソートです。 この機能を使うために FlashPlayer 8 以降の動作になりましたが、同様の内容で比較関数を自作すれば FlashPlayer 7 でも動作は可能です。 ちなみに完全一致については、 score_tbl[ 0 ].total_score というようにフィールドの値を見て、これがチェックボックスの総数と同じであれば完全一致であると判断することができます。 Check_Compare 関数内で、選択するべき項目を正しく選択しているかどうかを調べ、一致している数を数える処理を追加しました。 この比較には、ビット演算の & ( AND )を利用しています。 ビット演算は、2つの2進数を1桁ずつ比較し、両者の関係で 1 または 0 が決まる演算です。 今回は対象の数値がもともと 1 か 0 のどちらかなので、2進数の話はとりあえず気にしないでください。 演算の詳細はよそに譲りまして、AND は簡単にいうと、両方 1 の場合に 1 、それ以外は 0 になります。 選択されるべき項目はパターンデータの中では 1 で表わされ、選択状況の中でも選択されている項目はやはり 1 で表わされていますから、両方とも 1 であった場合に 1 (=選択するべき項目が正しく選択されている)と判断することができます。 それ以外は 0 ですので、1 だった場合のみ、選択されるべき項目の一致数が加算される仕組みです。 そういう、おまじないだと思ってくださっても構いません。 ご質問の主旨を勘違いしまして、大変失礼いたしました。
その他の回答 (2)
- DPE
- ベストアンサー率85% (666/776)
”チェックされているものだけを取り出して照合する”と考えると難しいので、全てのチェックボックスの選択状況を集めたデータを作り、同じ数のデータ同士で比較してはいかがでしょう。 例えば、8個のチェックボックスがあり、次のように選択されているとします。 ■が選択されているボックスです。 ■ ■ ■ ■ □ □ □ □ 選択されている■を1、選択されていない□を0に置き換えると、この選択状況は 1 1 1 1 0 0 0 0 と、数字で表すことができます。 これを、1つずつ配列変数の要素に格納します。 照合するパターンも同様に、選択されていてほしい項目のところを 1 に、選択するべきではない項目を 0 として、チェックボックスと同じ数だけ、配列変数を使ってパターンデータを用意します。 すると、選択状況もパターンデータも同じ要素数のデータの集まりになりますから、1つずつ照合し、一致している数を集計することも簡単にできます。 true と false でもいいのですが、パターンを記述する際にプログラムが見辛くなることがありますので、1 と 0 がオススメです。 照合しながら、一致している数を数えます。 一致している数がチェックボックスの総数と同じであれば、完全一致です。 また、この数が最も多かったものが、一致している項目が最も多かったパターンと判断することができます。 ----- 作り方の一例です。 チェックボックスはさしあたって、Flash 8 以降に付属の CheckBox コンポーネントを使います。 CheckBox のインスタンスには、共通の文字列+ 0 からの通し番号 で名前を付けます。ここでは仮に、チェックボックスは8つ、インスタンス名は cbox0 ~ 7 、とします。 ボタンを1つ作り、このボタンを押すことで照合を開始するものとします。ボタンのインスタンス名は”btn”とします。 インスタンスを置いたタイムラインに、次のスクリプトを記述します。 このスクリプトは、フレームに記述してください。 (↓ 各行頭に全角のスペースが入っています。コピーする際は、全て、半角のスペースかタブに置き換えてください) //*** /* 初期設定 */ //チェックボックスの選択状況を格納する配列 var check_status:Array = new Array(); //パターンデータ //最後の要素はパターン名 var check_ptt:Array = [ [ 1 , 0 , 1 , 0 , 1 , 0 , 1 , 0 , "サンプルA" ] , [ 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , "サンプルB" ] , [ 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , "サンプルC" ] ]; //チェックボックスの総数 var box_max = 8; //チェックボックスが配置されているタイムラインを保持 var box_line = this; /* 照合処理 */ function Check_Compare():Void { var i:Number , j:Number; var score:Number , score_max:Number , ptt_num:Number; //評価の最大値と現在評価が最高のパターン番号(ptt_nuum)の初期化 score_max = 0; ptt_num = 0; //選択状況とパターンを総当たりで照合する for( i = 0 ; i < check_ptt.length ; i++ ) { for( j = 0 , score = 0 ; j < box_max ; j++ ) { //照合処理 //一致していた場合、評価が+1、それ以外は加算されない score += Number( check_ptt[ i ][ j ] == check_status[ j ] ); } //評価を比較し、高ければ記録を更新 if( score > score_max ) { score_max = score; ptt_num = i; } } /*ここに、評価を利用する処理を書く 今回は一致した数が最も多かったパターンの名前を出力*/ trace( "一致数の最も多いパターンは " + check_ptt[ ptt_num ][ box_max ] ); } /* 照合開始ボタンの処理 */ btn.onRelease = function():Void { var i:Number; //選択状況を配列変数に格納 //選択されている場合1、されていない場合は0を入れる for( i = 0 ; i < box_max ; i++ ) { check_status[ i ] = Number( box_line[ "cbox" + i ].selected ); } //パターンと照合する Check_Compare(); }; //*** スクリプトの解説です。 選択状況とパターンを格納する配列変数を、それぞれ用意します。 パターンは2次元配列変数にすると、ループを利用して総当たりでチェックしやすくなります。 今回は、各パターンの最後にパターンの名前を記録しています。不要でしたら削除してください。 照合を開始するボタンが押された時に、まず、全てのチェックボックスの選択状況を全部、配列変数 check_status に格納します。 選択されている数のチェック処理等があれば、この前に入れてみてください。 選択状態を表す selected プロパティには true か false が入っているので、 Number という関数を使って 1 と 0 に変換して入れます。true は 1 、false は 0 に変換されます。 照合は、選択状況を格納した後に呼び出す Check_Compare という関数で行います。 for ループを二重にして、選択状況と全てのパターンを総当たりで照合します。内側の j のループで1つ1つのデータを取り出し、外側の i のループを利用して3種類全てのパターンを照合します。 実際に照合しているのは、内側 j のループ内の score += Number( check_ptt[ i ][ j ] == check_status[ j ] ); ↑ この部分です。 選択状況もパターンも、選択されているところを 1 、されていないところを 0 としてデータにしていますので、==演算子で等しいかどうかを見ることで照合できます。 == の演算の結果は、両者が同じ(=等しい)ならば true 、それ以外は false です。 この結果を Number 関数で 1 または 0 に変換し、score という変数に加算して、一致している数を集計します。一致していれば +1 されますが、不一致なら 0 なので score の値は変化しません。 従って、この score の値が一番大きいものが、一致している数が最も多かったパターン、ということになります。 上記のスクリプトではさしあたって、一致した数が最も多いパターンを検出します。 一致した数の最大数を保持する変数と、パターンの番号を記録する変数を用意しておきます。上記の例では、score_max と ptt_num という変数です。 1つのパターンの照合が終わる(= j のループ終了後)たびに、今調べたパターンとの一致した数である score と、これまでに出た最大数を持つ score_max の値を比較します。記録されている最大値よりも今回の score の方が大きい場合はこちらを最大値として残し、同時に、このパターンの番号である i の値も記録しておきます。 こうして最後まで総当たりで見た時、つまり外側 i のループ終了時に ptt_num に入っている番号が、最も一致している数が多かったパターンの番号になります。 なお、上記のスクリプトでは、同点だった場合は先に見つかった方が優先されます。 後で見つかった方を優先したい場合は、score と score_max を比較する部分を if( score >= score_max ) ↑ このように変更してください。 冒頭に書きました通り、一致した数である score の値がチェックボックスの総数と等しければ、完全に一致したということです。 完全一致を判断したい場合に利用してみてください。 例えばこの作例では、全部のチェックボックスを選択すると、score の値はいずれも 4 になり、3つとも同点になります。 先 / 後に見つかったものを優先する程度のことならば、比較演算子を > や >= にするだけで実現できますが、それ以外のことで評価したい場合は、他に優劣を決める要素(例えば、ある項目を選択していたものほど評価が高い、など)が必要になると思います。
お礼
回答頂きありがとうございます!教えて頂いたScriptで期待通りの動きができました、本当に詳しく書いて頂いてありがとうございます。 >選択されている■を1、選択されていない□を0に置き換えると、この選択状況は >1 1 1 1 0 0 0 0 >と、数字で表すことができます。 >これを、1つずつ配列変数の要素に格納します。 まさに目から鱗の思いで感動しました、そのやり方があったのかと今後の考え方の参考にさせて頂きます。その他にも色々と勉強になる部分があり、助かりました。 追加で書いて頂いたものをベストアンサーとさせて頂きます。 お忙しいところ、ご教授いただきありがとうございました。
- BlurFiltan
- ベストアンサー率91% (1611/1754)
チェックボックスのインスタンス名や値の設定方法などなどによって 値の取得方法は変わるのでパスします(書けません)。 ですから 配置したチェックボックスのチェック結果からは すでに > A配列[1,4,5,6,7,8] > B配列[1,2,3,4,5,6,7,8] > C配列[1,2,8,9,10,11] などの配列は取得できているものとします。 それと > 結果として > ○完全一致の場合の処理 > ○一致項目が多い場合の処理 この2行の具体的な意味がよく理解できないため この部分はパスさせていただきます。 > ○3つとも同じ場合の処理 これはなんとなくわかる気がするので 私なりの解釈を下記スクリプトに入れています。 ステージ上に用意する「判定をするボタン」のインスタンス名は「btn」であるものとします。 その「btn」が存在するタイムライン(_root なら _root)の フレームに書くスクリプト例です。 //--------------------------------------------- //アンサー配列「ans_arr」を用意 var ans_arr:Array = [1, 2, 3, 4, 6, 8]; //解答の配列「A_arr」「B_arr」「C_arr」の要素を //何らかの方法で取得しできているものとする var A_arr:Array = [1, 4, 5, 6, 7, 8]; var B_arr:Array = [1, 2, 3, 4, 5, 6, 7, 8]; var C_arr:Array = [1, 2, 8, 9, 10, 11]; //ボタン「btn」クリック時の動作 btn.onRelease = function() { //もしチェックが5個以下(5個も含める)のものがある場合は if (A_arr.length<=5 || B_arr.length<=5 || C_arr.length<=5) { //この関数を抜ける(何もしない) return false; } // //配列「A_arr」「B_arr」「C_arr」と //その各配列名と //各アンサーと同じ個数をカウントする変数を入れる //オブジェクトをまとめた配列「rec_arr」を作成 var rec_arr:Array = new Array(); rec_arr[0] = {arr:A_arr, str:"A_arr", cnt:0}; rec_arr[1] = {arr:B_arr, str:"B_arr", cnt:0}; rec_arr[2] = {arr:C_arr, str:"C_arr", cnt:0}; // //「ans_arr」の各要素を「@(何でも良い)」区切りの文字列にする var ans_str:String = ans_arr.join("@"); // //「rec_arr」内のループ(「A_arr」~「C_arr」に関するループ) for (var i:Number = 0; i<rec_arr.length; i++) { for (var j:Number = 0; j<rec_arr[i].arr.length; j++) { //もし「ans_str」に「A_arr」~「C_arr」の各要素があれば if (ans_str.indexOf(rec_arr[i].arr[j]) != -1) { //その配列対応のcntに1を加算 rec_arr[i].cnt++; } } } // //配列「rec_arr」を cnt を数と見たキーとして降順でソート rec_arr.sortOn("cnt", Array.DESCENDING | Array.NUMERIC); // //---結果を出力--- // ○3つとも同じ場合の処理 if (rec_arr[0].cnt == rec_arr[1].cnt && rec_arr[1].cnt == rec_arr[2].cnt) { trace("カウントは全て"+rec_arr[0].cnt+"で同じです。"); //2つが同じ場合の処理 } else if (rec_arr[0].cnt == rec_arr[1].cnt) { trace("カウントが最多の配列…"+rec_arr[0].str+"と"+rec_arr[1].str); trace("最多カウント数…"+rec_arr[0].cnt); } else { trace("カウントが最多の配列…"+rec_arr[0].str); trace("最多カウント数…"+rec_arr[0].cnt); } }; //--------------------------------------------- ・ActionScript 2.0 ・Flash MX 2004 以上で使用可 ・Flash Player 6 以上で動作可 「制御」→「ムービープレビュー」で ボタン「btn」をクリックしてもらうと trace の出力結果が見えると思います。
お礼
ご回答頂きありがとうございます! 詳しくScriptのサンプルまでご教授頂きありがとうございます。解決方法に色々なやり方があるんだなと、とても勉強になりました。 お忙しいところ、ありがとうございました。
お礼
ベストアンサーにさせて頂きました、スクリプトの解説まで書いて頂き、本当にありがとうございました。