• 締切済み

2次元配列で2項目についてソートのやりかたについて

こんにちは. VS2005 C++ MFC ダイアログベースでソフトを作成しています. CString型の配列 Array[100000][3] を定義し, CSVファイルから読み込んだ値を格納しています. 1列目 X座標 2列目 Y座標 3列目 結果 ファイルから読み込んだデータは以下のように y優先でxとyの値で昇順に並んでいます. _____[0] [1] [2] [0] 200 100 OK [1] 201 100 OK [2] 202 100 OK [3] 200 101 NG [4] 201 101 OK [5] 202 101 OK [6] 201 102 NG [7] 202 102 OK … これを以下のように x優先でxとyの値で昇順に並び変えたいのですが どのようにすればよいでしょうか? _____[0] [1] [2] [0] 200 100 OK [1] 200 101 NG [2] 201 100 OK [3] 201 101 OK [4] 201 102 NG [5] 202 100 OK [6] 202 101 OK [7] 202 102 OK かつ,100000行もあるのでスピードが速い方法だと助かります. 具体的なコードもお願いいたします.

みんなの回答

回答No.5

#1です。 できませんでしたか。 reinterpret_castがうまくいかなかったんでしょうかね? Array[100000][3]を動的に確保してるとか? まあ、reinterpret_castは環境依存なので、 うまくいかなくても仕方が無いですね。 しょうがないので、普通にコピーしますか。 RowT *rowp = reinterpret_cast<RowT *>(Array); を削除。 vector<RowT> v(rowp, rowp+100000); を削除して代わりに、 vector<RowT> v(100000); iter = v.begin(); for(int i=0;i<100000;i++){ for(int j=0;j<3;j++){ iter->dt[j] = Array[i][j]; } iter++; } 後は同じ、でできませんかね? あと#1お礼の所に書いてある bool operator<() で戻り値を戻さない場合がありますね。 最後のelseは書いたほうが良いです。

komehon
質問者

お礼

おそくなりすいません。 sort(v.begin(), v.end()); の前までは値が入っていたのですが、 ソート後に int i = 0; for(iter = v.begin(); iter != v.end(); iter++){ SortedArray[ i ][ 0 ] = iter->dt[ 0 ]; SortedArray[ i ][ 1 ] = iter->dt[ 1 ]; SortedArray[ i ][ 2 ] = iter->dt[ 2 ]; i = i + 1; } とすると値が入っていませんでした。 struct RowT { CString dt[3]; }; をCStringにしたのがいけなかったのか ここをintにするとソート後にも値が入っており、 うまく並べ替えられるようになりました。 bool operator<()のところはelseが必要ですね。すいません。 このたびはいろいろ教えてくれてどうもありがとうございました。

  • 7o8
  • ベストアンサー率55% (5/9)
回答No.4

> tmp[X]=atoi(Array[X][0])<<16+atoi(Array[X][1]) > とはどういうことでしょうか? 処理系にもよりますが、MS C++なら intで32bitを扱えます。 32bitをX,Yで16bitずつ(実質15bitずつですが)使用するようにすれば X優先でX,Yの値をソートするのに簡単ですよね?ということです。 普通に10進数でも Xを上位3桁、Yを下位3桁の6桁で表現しても 同じことです。 #X,Yの桁がいくつってのが肝になります。 ちなみに今回の場合は X,Y共に 0~32767までの値に収まっている必要があります。 コードのほうですが、少しはご自分で考えてみましょう。 今時間がないため、提示することができないのですが、 まずはアルゴリズムが理解できればそーは難しくないはずです。

komehon
質問者

お礼

>処理系にもよりますが、MS C++なら intで32bitを扱えます。 >32bitをX,Yで16bitずつ(実質15bitずつですが)使用するようにすれば >X優先でX,Yの値をソートするのに簡単ですよね?ということです。 なろほど、そういうことでしたか。 ビットを扱うのは慣れていないの勉強しておきます。 今回の質問ですがICE_FALCONに教えていただいたできるようになりました。 一応int型のデータを並べ替えるように修正したので さらに処理速度が必要なら、7o8さんの方法で検討したいと思います。 このたびはどうもありがとうございました。

  • 7o8
  • ベストアンサー率55% (5/9)
回答No.3

C言語的な考え方ですが、私なら以下のように作成します。 Array[100000][3]に対応する配列を2つ用意しましょう。 ここでは tmp[10000],idx[10000]とします。 X,Y座標がどの程度の大きさになるのか?次第ですが、例にあるように 3桁数字程度であれば、tmp[],idx[]はint型で以下のように設定します。  tmp[X]=atoi(Array[X][0])<<16+atoi(Array[X][1])  idx[X]=X tmp[X]を並べ替え、その結果をidx[X]にも反映させれば、Array[idx[X]][3]とすることで 並べ替えられたことになります。 高速化のポイントは 比較はCPUが扱うことができる最も得意なデータで あるint型を用いることです。 もし例と異なり、数値が3桁整数でない、もしくは小数点含むデータで あるなら素直にICE_FALCONさんが提示されている方法がいいかと思います。

komehon
質問者

お礼

ありがとうございます。 すいませんまだ不慣れなもので コードを全部載せてもらえると助かります。 とりわけ tmp[X]=atoi(Array[X][0])<<16+atoi(Array[X][1]) とはどういうことでしょうか? シフト演算子?16ビットシフトするということでしょうか?

回答No.2

#1です。 ・・・3列目いらなかったですね。 bool operator < () の深さを一つ減らしてください。

回答No.1

速くは無いですが、std::sortを使うのが簡単です。 私はMFCの環境無いので、とりあえずstd::stringで・・・。 struct RowT { string dt[3]; }; bool operator<(const RowT &rowx, const RowT &rowy) { if(atoi(rowx.dt[0].c_str()) < atoi(rowy.dt[0].c_str())){ return true; }else if(atoi(rowx.dt[0].c_str()) > atoi(rowy.dt[0].c_str())){ return false; }else{ if(atoi(rowx.dt[1].c_str()) < atoi(rowy.dt[1].c_str())){ return true; }else if(atoi(rowx.dt[1].c_str()) > atoi(rowy.dt[1].c_str())){ return false; }else{ if(atoi(rowx.dt[1].c_str()) < atoi(rowy.dt[1].c_str())){ return true; }else if(atoi(rowx.dt[1].c_str()) > atoi(rowy.dt[1].c_str())){ return false; }else{ return false; } } } } //-------------- //main ・・・・ RowT *rowp = reinterpret_cast<RowT *>(Array); vector<RowT>::iterator iter; vector<RowT> v(rowp, rowp+100000); sort(v.begin(), v.end()); for(iter = v.begin(); iter != v.end(); iter++){ cout << iter->dt[0] << ";" << iter->dt[1] << ";" << iter->dt[2] << endl; } ・・・reinterpret_castがうまくいくかは保証できません・・・。

komehon
質問者

お礼

ありがとうございます。 ICE_FALCONさんのサンプルを若干変更しました。 struct RowT { //CStringに変更////////////// CString dt[3]; ///////////////////////////// }; bool operator<(const RowT &rowx, const RowT &rowy) { //深さを変更///////////////////////////////////////////////// if(atoi(rowx.dt[0].c_str()) < atoi(rowy.dt[0].c_str())){ return true; }else if(atoi(rowx.dt[0].c_str()) > atoi(rowy.dt[0].c_str())){ return false; }else{ if(atoi(rowx.dt[1].c_str()) < atoi(rowy.dt[1].c_str())){ return true; }else if(atoi(rowx.dt[1].c_str()) > atoi(rowy.dt[1].c_str())){ return false; } } } } ////////////////////////////////////////////////////////////// } //-------------- //main ・・・・ RowT *rowp = reinterpret_cast<RowT *>(Array); vector<RowT>::iterator iter; vector<RowT> v(rowp, rowp+100000); sort(v.begin(), v.end()); //配列に格納するよう変更/////////////////////////// int i = 0; for(iter = v.begin(); iter != v.end(); iter++){ SortedArray[ i ][ 0 ] = iter->dt[ 0 ]; SortedArray[ i ][ 1 ] = iter->dt[ 1 ]; SortedArray[ i ][ 2 ] = iter->dt[ 2 ]; i = i + 1; /////////////////////////////////////////////////// } としたところ,配列SortedArrayにはなにも入っていませんでした。 (すべて""になっていました。) なにかおかしいところがありますでしょうか?

komehon
質問者

補足

ちなみに RowT *rowp = reinterpret_cast<RowT *>(Array); の時点ではArrayに正常に値が入っています。

関連するQ&A

  • 配列のソート

    Javaのプログラムで、以下のように半径rでソートして並び替えて出力したいのですがどうやって作ればいいのでしょうか? ご教授願います。 0x座標は0 y座標は0 半径は48 1x座標は1 y座標は2 半径は42 2x座標は2 y座標は4 半径は5 3x座標は3 y座標は6 半径は75 4x座標は4 y座標は8 半径は21 0x座標は2 y座標は4 半径は5 1x座標は4 y座標は8 半径は21 2x座標は1 y座標は2 半径は42 3x座標は0 y座標は0 半径は48 4x座標は3 y座標は6 半径は75 半径の値はランダムです 自分では以下まで作りました。なるべく以下の形は変えないようにしたいです。 class Circle{ private int x,y,r,j; private static int i=0; Circle(int px,int py,int pr) { x=px; y=py; r=pr; } public static void show(Circle c){ System.out.println(i+"x座標は"+c.x+" y座標は"+c.y+" 半径は"+c.r); i++; } public static void sort(Circle c){ } } class Sample{ public static void main(String args[]) { Circle[] a=new Circle[5]; for(int i=0;i<a.length;i++) { a[i]=new Circle(i,2*i,(int)(Math.random()*100)); a[i].show(a[i]); } } }

  • 多次元配列でソートしたい

    たとえば、Yahooオークションとかで、「商品名」「価格」「残り日数」が表示されていて、 それぞれをクリックすると、その列をソートして全体を昇順・降順に並べ替えてくれますよね。 あれを自前のCGIで実現したいのです。 たとえば、3次元配列$hoge[X][Y][Z]を定義し、ここがクリックされたらXをキーにソート、ここがクリックされたらYでソートということをやりたいと思っているのですが、当然こういう機能は無いわけで、自分で作らなくてはいけません。 連想配列とかポインタとか色々考えたのですが、うまく行かず・・・。 どのような実装方法があるでしょうか、アイデアをお聞かせ願えたら嬉しいです。

    • ベストアンサー
    • Perl
  • 2次元配列CSVのソート

    2次元配列で次のCSVファイルがあります。 フォームから入力したのですが、txtファイルには項目名(列名)が保存されていません。 taro,10,119 jiro,10,90 hanako,9,120 momoko,11,98 saburo,12,111 natuyo,10,130 sirou,8,88 このデータを年齢順、及び身長順に並べ替えをしたいのです。 列の名前がないので、手動でtxtファイル1行目に simei,toshi,shinchou と追記して 01: <?php 02: $data = "c:\××\××\shinchou.txt"; 03: $array = file($data); 04: foreach($array as $key => $row){ 05: $toshi[$key] = $row["toshi"]; 06: $shinchou[$key] = $row["shinchou "]; 07: } 08: print_r($array); 09: array_multisort($toshi,SORT_ASC, $shinchou,SORT_ASC, $array); 10: ?> と実行しましたが、 Array ( [0] => simei,toshi,shinchou  [1] => taro,10,119 ・・・・と、print_r($array)の結果が出るだけで、ソートが出来ません。 CSVファイルで項目名(列名)が無い場合の並べ替えはどのようにすれば良いでしょうか。 mySQLなどを利用しないと並べ替えは出来ないでしょうか。

    • ベストアンサー
    • PHP
  • 2次元配列の文字"列"の初期化方法

    こまかな話しかもしれないのですが、2次元配列の文字列代入で、 char *array2 = {"Jan", "Feb", "March"}; //NG はNGで char *array2[3] = {"jan,", ...}; //OK なのはどうしてなのでしょうか? 1: "[3]"は明示しなくとも代入される値から分かるという理由で省略してはいけないのでしょうか? また、 2: 一次元の場合 char *array = "aaaaa"; とできるのにどうして2次元ではNGなのか、がピンと来ません。 すみませんが、宜しくお願い致します。

  • キャストについて str = (CString*)("999") ;

    環境 WIN98 VC++6.0 MFC にて いつもお世話になります。 先日質問したばかり(QNo.682705)なのですが、やはり納得できないことがあるのでお願いします。 分かっている人からみれば、おかしな疑問と思われるかも知れませんが、私にとっては素朴に疑問が生じてしまいます。 *************************** 以下2つのコードのうち、<A>は文法的にOKで<B>がNGな理由が知りたいです。 <A> CString* str ; str = (CString*)m_array.GetAt(i) ; //OK <B> CString* str ; str = (CString*)("999") ; //NG <A>は、m_arrayの要素にCString*を入れていて、初めて成り立つ式です。 と教わりましたが、むしろ私にはCString*以外が入っているため、CString*のキャストしていると思える。 CString*が入っているのなら、キャストする必要は無いのではないでしょうか? ネット上で見つけたコードなため、実際の値やm_arrayの宣言がどうなっているかは確認出来ません。 そして、<A>がおかしなコードでは無いという大前提にたつと、<A>は別の表現をすると <A> str = (CString*)(CString*以外のポインタ) ; となります。 そうすると<B>のコードも、"999"は999の文字列が入っているアドレスを指すポインタであるという考えが正しいとすると、 <B> str = (CString*)(999をさすポインタ) ; となり、おかしなコードではないと思えるのですが、考え方のどこがおかしいのでしょうか? ************************** 以下のことを教わった上であえて聞いています。 str = (CString*)("999"); は、リテラル文字列をつっこもうとしています。 リテラル文字列とCStringはまったく別物です。

  • 二次元配列が上手くいきません

    Sample.txt 2 2 10 01 php <?php $handle = fopen('sample.txt','r'); // ファイルを開いてファイルポインタを取得 $contents = fread( $handle, 1024 ); // ファイル内容を1024バイト分読み込んで変数に格納 fclose( $handle ); // ファイルを閉じてファイルポインタを破棄 $start_part=array_map("trim",explode("\n",$contents));//$start_partは初期画像の行の配列 改行を削除 $r = $start_part[0];//横サイズを読み込む $g = $start_part[1];//縦サイズを読み込む $start[][]=""; //g行r列の2次元配列を作成 start[x][y],end[x][y]; for($j=0;$j<$g;$j++){ for($i=0;$i<$r;$i++){ $start[$i][$j] = substr($start_part[2+$j],$i,1); } } print_r($start); ?> xamppでphpの勉強をしている初心者です。 理想では$start[0][0]=1 $start[0][1]=0 $start[1][0]=0 $start[1][1]=1となってほしいのですが、 Array ( [0] => Array ( [0] => ) ) としか表示されず困っています。どこを直せばよいのでしょうか。どこが良くないのでしょうか。 ご教授ください。よろしくお願いします。

    • 締切済み
    • PHP
  • 多次元配列の中で条件に合う要素の値を全て別の配列に入れるには

    表題の処理を行うにはどうしたら良いでしょうか。 例: 要素名がxである値を別の配列にいれる input ( [a] => aaa [b] => Array ( [x] => 1 [y] => 2 ) [c] => Array ( [x] => 8 ) ) output ( [0] => 1 [1] => 8 )

    • ベストアンサー
    • PHP
  • 構造体型二次元ベクタのソート

    構造体型の二次元のベクタをソートしたいのですがやりかたがよくわかりません。 struct coordinate{ int x; int y; }; vector< vector<coordinate> > dbVec; 上記のコードで、 dbVec[val][0].x  のxを昇順にval列をソートしたいです。 よろしくお願いします。

  • PHP 多次元配列のソート

    $array = array( array("address" =>"eeee@dddd.ddd","name" => "あいう"), array("name" => "はざま","address" => "cccc@dddd.ddd"), array("name" => "かきく","address" => "tttt@ccc.eee"), array("name" => "さく","address" => "bbbb@dddd.ddd"), array("name" => "あか","address" => "aaaa@dddd.ddd") ); 上記のような多次元配列があった場合 sort($array); とすると 以下のようなデフォルトの配置が Array ( [0] => Array ( [address] => eeee@dddd.ddd [name] => あいう ) [1] => Array ( [name] => はざま [address] => cccc@dddd.ddd ) [2] => Array ( [name] => かきく [address] => tttt@ccc.eee ) [3] => Array ( [name] => さく [address] => bbbb@dddd.ddd ) [4] => Array ( [name] => あか [address] => aaaa@dddd.ddd ) ) 上記の並びが Array ( [0] => Array ( [address] => eeee@dddd.ddd [name] => あいう ) [1] => Array ( [name] => あか [address] => aaaa@dddd.ddd ) [2] => Array ( [name] => かきく [address] => tttt@ccc.eee ) [3] => Array ( [name] => さく [address] => bbbb@dddd.ddd ) [4] => Array ( [name] => はざま [address] => cccc@dddd.ddd ) ) nameキーの値をもとにあいうえお順にならびかえられます。 がこれをnameキーではなく addressキーで並び替えたいと思ったとき、 usort($array , function($a,$b){ if($a["address"]< $b["address"]){ return -1; }else{ return 1; } } ); と上記のようのおこなうと Array ( [0] => Array ( [name] => あか [address] => aaaa@dddd.ddd ) [1] => Array ( [name] => さく [address] => bbbb@dddd.ddd ) [2] => Array ( [name] => はざま [address] => cccc@dddd.ddd ) [3] => Array ( [address] => eeee@dddd.ddd [name] => あいう ) [4] => Array ( [name] => かきく [address] => tttt@ccc.eee ) ) とうまくaddressキーでabcdの順にソートできています。 次に usort($array , function($a,$b){ return strcmp($a["address"],$b["address"])? -1:1; } ); と上記のようにstrcmp関数を使うと Array ( [0] => Array ( [name] => あか [address] => aaaa@dddd.ddd ) [1] => Array ( [name] => さく [address] => bbbb@dddd.ddd ) [2] => Array ( [name] => かきく [address] => tttt@ccc.eee ) [3] => Array ( [name] => はざま [address] => cccc@dddd.ddd ) [4] => Array ( [address] => eeee@dddd.ddd [name] => あいう ) ) うまくソートできませんでした。 この、直接 $a, $bの大小を条件とした場合と strcmp — バイナリセーフな文字列比較をおこなうstrcmp とは、どのような処理の違いがあるのでしょうか?

    • ベストアンサー
    • PHP
  • Perlで配列の添え字を抽出したい

    Perl初心者で、既出の質問かもしれませんが、ご教授願います。 以下のように"*"が入っている値を抽出する処理があります。 ーーーーーー処理ーーーーーー @array = ('aaa', 'b*b', 'ccc', 'dd*'); foreach (@array) { if ($_ =~/\*/) { print "OK\n"; } else { print "NG\n"; } } ーーーーーーーーーーーーーーーー ーーー結果ーーー NG OK NG OK ーーーーーーーー <質問> 上記結果より、OKとなった値の配列(添え字)を取得するにはどのようにすれば宜しいでしょうか? 宜しくお願い致します。

    • ベストアンサー
    • Perl

専門家に質問してみよう