• 締切済み
  • 困ってます

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行もあるのでスピードが速い方法だと助かります. 具体的なコードもお願いいたします.

共感・応援の気持ちを伝えよう!

  • 回答数5
  • 閲覧数2398
  • ありがとう数5

みんなの回答

  • 回答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は書いたほうが良いです。

共感・感謝の気持ちを伝えよう!

質問者からのお礼

おそくなりすいません。 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が必要ですね。すいません。 このたびはいろいろ教えてくれてどうもありがとうございました。

関連するQ&A

  • cygwinでのテキスト処理方法がわかりません。

    CSVファイルで1~3列目に値が入っています。1列目と2列目が同じ行を抜き出し、同じ行の3列目の値を足し合わせる事は簡単にできますでしょうか? たとえば 1 0 10 1 0 20 1 1 5 2 0 5 2 1 10 の構造で、1列目が1で、かつ2列目が0の行について足し合わせた値(この場合;30)をスクリプトで処理したいのですが? どうぞよろしくお願い致します m(..)m

  • Perlでファイルの列を削除する。

    どのように書けばいいかわからないので教えてください。 ","で区切られたcsvファイルがあるとします。(file.csv) そのファイルは全部で5列ありますが、4列目と5列目は値が入っている場合と無い場合があります。(1~3列目は必ず値は存在します。) このファイルの1列目と2列目を削除して、3列目から5列目だけのファイルを作成したいのですが、どうすればいいのでしょうか? よろしくお願いします。

    • ベストアンサー
    • Perl
  • Rubyで配列をソートする

    15(tab)5634(改行) 24(tab)4446(改行) 24(tab)8357(改行) 24(tab)3287(改行) 56(tab)5465(改行) 56(tab)1324(改行) 56(tab)7544(改行) 上記のように1行にtabで区切られた2つの数値が並んでいるテキストファイルがあります。 このファイルを、Rubyを使って1列目が同じ数字の行ごとにソートしたいのですが、できなくて困っています。 上の例でしたら、1列目が24の3行を2列目の数値をキーとしてソート、1列目が56の3行を2列目の数値をキーとしてソートするということです。 一行ずつ読み込んで、array = line.split(/\t/)でタブでくぎって配列に格納するスクリプトを書いていたのですが、どうしてもできないので、力を貸していただけないでしょうか。 よろしくお願いします。

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

> 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までの値に収まっている必要があります。 コードのほうですが、少しはご自分で考えてみましょう。 今時間がないため、提示することができないのですが、 まずはアルゴリズムが理解できればそーは難しくないはずです。

共感・感謝の気持ちを伝えよう!

質問者からのお礼

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

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

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さんが提示されている方法がいいかと思います。

共感・感謝の気持ちを伝えよう!

質問者からのお礼

ありがとうございます。 すいませんまだ不慣れなもので コードを全部載せてもらえると助かります。 とりわけ 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がうまくいくかは保証できません・・・。

共感・感謝の気持ちを伝えよう!

質問者からのお礼

ありがとうございます。 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にはなにも入っていませんでした。 (すべて""になっていました。) なにかおかしいところがありますでしょうか?

質問者からの補足

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

関連するQ&A

  • エクセルマクロの質問です。

    例えば、A.xlsというファイルに01.csv,02.csv,・・・,20.csvといういくつかのファイルからデータを取り出すのですが、A.xlsのシート1の1列目に01.csvの1列目を貼り付けて、01.csvの2列目はA.xlsのシート2の1列目に貼り付けるようにシートをずらして行って、02.csvの1列目はA.xlsのシート1の2列目、02.csvの2列目はA.xlsのシート2の2列目というようにしたいのですが、どのようなプログラムがよいのでしょうか? エクセルマクロ初心者なので説明が不十分かも知れませんがよろしくお願いします。

  • 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はまったく別物です。

  • sumif関数とif関数と配列の使い方

    例えば、下記のように9行×3列のデータがあり、1列目が123かつ2列目がcであるものについて3列目を合計したいのですが(つまり300+600で900を算出する)、1セルに値を算出する方法があれば教えてください。 sumif関数とif関数と配列を使えばできそうな気がするんですが、やり方がよくわかりません。よろしくお願いします。 123  a  100 123  b  200 123  c  300 456  a  1000 456  b  2000 456  c  3000 123  a  400 123  b  500 123  c  600

  • エクセルファイルの1レコード(1行)を1csvファイルへ変換マクロ

    エクセルファイルの1レコード(1行)を1csvファイルへ変換し、エクセルファイルにあるレコード数分だけあるフォルダに自動作成するマクロを教えて下さい。 因みに、csvファイル名は、エクセルデータの『a列.csv』となるようにしたいです。 【例】 本日2007/11/13 ○○.xls A列 B列 C列 111 1 356 13 1 2 ・ ・ ・ ・ ・ ・ 111.CSV "2007/11/13(火)","1","356,"","","" 13.CSV "2007/11/13(火)","1","2,"","","" 変換後のcsvの中身は 1列目に、本日の日付 2列目に、1 3列目に、変換元のエクセルファイルの3列目 4、5、6列目に空白 という形式です。 どなたかお分かりになるかた、ご教授願います。

  • フォームに入力された値から、PHPでCSVデータを読んで表示させたい。

    フォームに入力された値から、PHPでCSVデータを読んで表示させたい。 現在、PHPでお申し込みフォームを作成中なのですが、どこのページから来たかを判別するための値から、そこのページ名を表示させたいのですが、うまくできません。 CSVファイルには1列目に値、2列目にページ名が書かれたものが、50行あります。その中から、 例えば値が5だったら、5行目の2列目に書かれているページ名を表示させたいのですが、どうしたらいいのか、教えていただきたいです。

    • ベストアンサー
    • PHP
  • matlabについて教えてください

    プログラミング初心者です。matlabについて教えてください いまmatlabのプログラム上に、x, y, z, という、それぞれ5行1列の変数があります。 これらをまとめて、linuxのテキストエディタ(geditなど)で読み込める1つのファイルを作りたいと思っています。 作りたいファイルは、1列目にx、2列目にy、3列目にz の値が並んでいるような感じです。 どうかやり方を教えて下さいますようお願いします。

  • エクセルで複数の条件に合致したセルを検索する方法

    いつもお世話になります。 以下のようなセルがあり、 1列目と2列目の値が合致した時の3列目のセル(例えば1列目が「a」で2列目が「2」の行の3列目の値「hh」)を別のシートに表示したいです。 VLOOKUPで検索すると、1列目の値のみが検索対象となってしまいますので、 そのやり方だと「gg」が表示されてしまいます。 関数の組み合わせでうまく値を検索・表示する方法はありますでしょうか a 1 gg a 2 hh a 3 ii a 4 jj a 5 kk a 6 ll a 7 mm b 1 oo b 2 pp b 3 pp b 4 rr b 5 ss b 6 tt b 7 uu よろしくお願いいたします。

  • USBメモリをさすと同時にUSB内のエクセルが立ち上がる様にすることは

    USBメモリをさすと同時にUSB内のエクセルが立ち上がる様にすることはできるでしょうか?また、列ごとに、CSVファイルに書き込むことはできるでしょうか?例えば、1列目は、1.csv、2列目は、2.csvのようにです。 ご教授のほどよろしくお願いします。

  • CSVファイルを読み込む

    .net VB 2010 初心者です。VB 6.0は、少々分かります。 よろしくお願い致します。 .net VB 2010を使用して、CSVファイルを読み込みたいのです。 列は固定、行は可変です。 配列で、buf(行,列)のように読み込みたいのです。 これだと、10行、3列目と実際とイメージが合致するからです。 これは、どのように実現可能か教えてください。 buf(10,3)ではなく、もっと良い方法があるのであれば、そちらをよろしくお願い致します。 列は、1列目:No.、2列目:フルネーム、3列目:略語、4列目:更新日 となっています。 なので、1行目のフルネームの取り出し、2行目の略語の取り出しでもOKです。 どうぞよろしくお願い致します。