• 締切済み
  • すぐに回答を!

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/)でタブでくぎって配列に格納するスクリプトを書いていたのですが、どうしてもできないので、力を貸していただけないでしょうか。 よろしくお願いします。

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

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

みんなの回答

  • 回答No.5

 ご質問から1列目は小さい順に並べられているものと仮定します。  また、入力データが"input.txt"というファイルに格納され、 出力データを"output.txt"にしているとすると、 以下のようなスクリプトで実行できると思います。 (字下げがなくなっているので、見にくいとは思いますが、ご了承ください) in1_file = open("input.txt","r") out1_file = open("output.txt","w") # 初期値設定 in1_ctr = 0 #入力件数 w_ctr = 0 #ソート件数 in1_key = nil #入力キー in1 = nil #入力した配列 in1_rec = Array.new #入力キー sv_key = nil #保存キー # キーブレイク時の処理 def s_break(in1_rec,out1_file) sort_rec = in1_rec.sort_by{|a| a_array = a.split("\t",-1) [a_array[1]] } sort_rec.each {|data| out1_file.print data,"\n" } end # 主処理 while (line1 = in1_file.gets) line1.chomp! in1 = line1.split("\t") in1_key = in1[0] in1_ctr += 1 # キーブレイク時 if ((in1_ctr != 1) && (sv_key != in1_key)) s_break(in1_rec,out1_file) w_ctr = 0 in1_rec = [] end sv_key = in1_key in1_rec[w_ctr] = line1 w_ctr += 1 end # 最終データの処理(入力データがある場合) if (in1_ctr != 0) s_break(in1_rec,out1_file) end # ファイルクローズ in1_file.close out1_file.close  あるいは、1列目を第1のキー、2列目を第2のキーとして昇順に並べ替えてもよいのであれば、 以下のようなスクリプトになります。 in1_file = open("input.txt","r") out1_file = open("output.txt","w") in1_ctr = 0 in1_rec = Array.new sort_rec = Array.new while (line1 = in1_file.gets) line1.chomp! in1_rec[in1_ctr] = line1 in1_ctr += 1 end sort_rec = in1_rec.sort_by{|a| a_array = a.split("\t",-1) [a_array[0].to_i,a_array[1].to_i] } sort_rec.each {|data| out1_file.print data,"\n" } in1_file.close out1_file.close 上記で、"[a_array[0].to_i,a_array[1].to_i]"としている箇所が整数で1列目を第1キーに、同じく整数で2列目を第2キーに指定している部分です。ご質問の例では、1列目と2列目でそれぞれ数字の桁数が同じでしたので、仮に「文字列型」として並べ替えても良いのであれば、"[a_array[0],a_array[1]]"とすることもできます。

参考URL:
http://www003.upp.so-net.ne.jp/NAMBOKU/ruby/ruby0243.html

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

関連するQ&A

  • 配列のソート

    Ruby初心者です。 例えば [12,38,121,273,13] [23,47,478,112,98] [56,73,227,556,12] [22,43,668,223,74] [33,13,393,763,91] を [12,38,121,273,13] [22,43,668,223,74] [23,47,478,112,98] [33,13,393,763,91] [56,73,227,556,12] のように第1列目の要素で配列ごとソートしたいのですが、私がやると、 [12,13,38,121,273] [22,43,74,223,668] [23,47,98,112,478] [13,33,91,393,763] [12,56,73,227,556] のように第一列の要素は一応ソートは出来ているのですが、 配列の中身まで並べ変わってしまいます。 配列ごとにソートするにはどうすれば良いのでしょうか?

  • 多次元配列のソートについて

    始めまして。 多次元配列のソート方法について分からないことがある為教えていただけないでしょうか。 $a[0] = array('2007/3/1','あ100','その他'); $a[1] = array('2007/3/1','あ200','その他'); $a[2] = array('2007/3/2','あ200','その他'); $a[3] = array('2007/3/2','あ300','その他'); $a[4] = array('2007/3/3','あ50','その他'); 上記のような配列があった場合、usort関数でやると、日付かその後ろの数値の値を元にソートできますが、両者の関係を持たせたソートは可能でしょうか。 結果としては $b[0] = "2007/3/3 あ50"; $b[1] = "2007/3/2 あ200"; $b[2] = "2007/3/2 あ300"; $b[3] = "2007/3/1 あ100"; $b[4] = "2007/3/1 あ200"; というようにしたいのです。 よろしくお願いします。

    • ベストアンサー
    • PHP
  • 配列のソートがしたい

    sort関数等調べたのですがうまくできません。 やりたいことは http://q.hatena.ne.jp/1155090363 ↑で見つけた事とそっくりなのですが・・・。 ------------------------------------------- arrItem[n] という配列の一つの要素の中に、 タブで区切られた10個程のデータが入っています。 arrItem[0] = "5 ^ 店名5 ^ 品名5 ^ 価格5 ^ 割引額5 ^・・・^ 備考5" arrItem[1] = "2 ^ 店名2 ^ 品名2 ^ 価格2 ^ 割引額2 ^・・・^ 備考2" arrItem[2] = "11 ^ 店名9 ^ 品名9 ^ 価格9 ^ 割引額9 ^・・・^ 備考9" 一列目はSEQ番号でユニークですが、順番が並んでいません。 この配列をSEQ番号で並べ替えたいのですが、 sortだと文字列比較のためか桁数の違う数字の並べ替えが 上手くできません。数値としてのソート方法 が分かる方いらっしゃいましたらご教授願います。 もし可能なら、1列目を数値降順にしたり昇順にしたり、 また2列目を五十音順にソートしたり、 また4列目を価格の安い順にソートしたり と応用も可能ならばご教授願いたいです。 宜しくお願い致します。

  • 回答No.4
  • n333
  • ベストアンサー率0% (0/0)

1列目はソートしたくないということと理解しました。 (インデントされないようなので見難くてすみません) array = [] old = nil while line = gets group, key = line.chomp.split(/\t/) unless old == group array.sort_by{|a|a.to_f}.each do |k| puts [old,k].join("\t") end old = group array = [] end array << key end array.sort_by{|a|a.to_f}.each do |k| puts [old,k].join("\t") end

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

  • 回答No.3
  • notnot
  • ベストアンサー率47% (4667/9812)

各カラムの数字の桁数が例示のように各行固定なら、 puts IO.readlines("ファイル名").sort でいいのでは? 各カラムが2文字4文字と固定長とは限らず、文字列としてで無く数値として比較しないといけないとすると、 puts IO.readlines("ファイル名").sort_by{|line| line.chomp.split(/\t/).map{|x| x.to_i }}

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

  • 回答No.2
  • sholmes
  • ベストアンサー率81% (89/109)

正規表現でも文字列でも、\tメタ文字を用いて区切るやり方で問題無いと思いま すよ。 どのあたりでうまくいかない感じですか? 一例だけ http://ideone.com/Ii63o

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

  • 回答No.1

array = line.split("\t") じゃね? と、勘で回答

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

関連するQ&A

  • 2次元配列 ソート

    はじめまして。 FLASH8を使っています。 2次元配列のソートがうまくいかず困っています。 Array[0][0] = "かかか"; Array[0][1] = "ききき"; Array[0][2] = "くくく"; Array[1][0] = "あああ"; Array[1][1] = "いいい"; Array[1][2] = "ううう"; とあって2番目の要素(「ききき」「いいい」の部分です)をキーとしてArray[n]を昇順にソートしたいのです。 この場合結果としては、 Array[0][0] = "あああ"; Array[0][1] = "いいい"; Array[0][2] = "ううう"; Array[1][0] = "かかか"; Array[1][1] = "ききき"; Array[1][2] = "くくく"; となります。 ご存知の方がいらっしゃいましたら教えてください。 よろしくお願いします。

    • ベストアンサー
    • Flash
  • 配列のソート

    下記のような形でデータを取得し結果を配列に格納し、 降順にソートしたいのですが、いい方法が見つかりません。いい方法はあるでしょうか。よろしくお願いします。 テーブル構造(test) ID|name |point|area| ==================== 1 |Aさん|56 | A | 2 |Bさん|12 | B | 3 |Cさん|24 | B | 4 |Dさん|34 | B | $sql = "select * from test"; $result = mysql_query($strSQL); while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) { ここで配列に格納 } 配列への格納方法と、pointの降順にソートする 方法が知りたいです。 最終的に、Aさん、Dさん、Cさん、Bさんと なるようにしたいです。

    • ベストアンサー
    • PHP
  • 配列をソートさせたとき、もう一方の配列も同じようにソートさせたい

    タイトルが意味不明で申し訳ありません。 二つの配列があるとします。 片方には文字列、もう片方には数値が記録されているもので、最大添え字は同じです。 この数値の大きい順に並べ替えを行いたいのですが、 name[0]とcount[0] name[1]とcount[1] ・ ・ をペアで並べ替えたいのですが、その方法が分かりません。 sort関数を使うとどうしても片方のみしかソートできないし、バブルソートを用いて試みましたが、どうも並び替えられません。 連想配列を使う考えもありましたが、2つの配列をどうやって一つのハッシュに格納すればいいか分からず断念しました。 バブルソートの方にバグがあるのかもしれませんが、何か方法があればご教授いただけると幸いです。 よろしくお願いします。 バブルソート部分のソース(配列は@filelistと@countを使用) # ソート処理 for($i=0;$i<$#filelist;$i++){ for($j=0;$i<$j;$j++){ if($count[$i]<$count[$i+1]){ $tmp=$count[$i]; $count[$i]=$count[$i+1]; $count[$i+1]=$tmp; $tmp=$filelist[$i]; $filelist[$i]=$filelist[$i+1]; $filelist[$i+1]=$tmp; $k=$j; } $i=$k; } }

    • ベストアンサー
    • Perl
  • 二次元配列のソート PHP

    タイトルのとおりソートを行ってくれる関数を探しております。 $buf[][]の二次元配列の変数を日付の降順に並べ替えたいのですが、そういった関数は用意されていますか? sort()、rsort()では不可能かと思います。 以下、二次元配列の値です。配列三番目の日付の降順で再格納したいです。 ( [0] => Array ( [0] => 1[1] => name1 [2] => 2006-08-18 ) [1] => Array ( [0] => 2 [1] => name2[2] => 2006-08-28 ) [2] => Array ( [0] => 3[1] => name3 [2] => 2006-08-18 ) [3] => Array ( [0] => 4 [1] => name4[2] => 2006-08-18 ) よろしくお願いいたします。

    • ベストアンサー
    • PHP
  • Visual C++を 用いたテキストファイル読み込み(応用)

    Microsoft Visual C++ 2008 Express Editionを使っています。 テキストファイルは 約5000行×6列の数値(のみ)になっております。(列間にスペースあり) いくつかある5000×6行テキストファイルの中から、ファイル名を入力することで任意のテキストファイルにアクセスし、さらに6列のデータをそれぞれ別の配列に格納するコンソールプログラムを考えていますが行き詰まっています。例えば、1列目を配列1、2列目を配列2、・・・といった具合です。 詳しい方、どうかよろしくお願いいたします。

  • Rubyで配列の各要素の中身を書き換えてコピー

    Rubyの配列の扱い方についてなのですが、 配列内の各要素(文字列)を更に細かい単位に分割してその中の1部を別の配列へコピーしようと思うのですがどうもうまくいきません。 具体的には array1["http://www.google.co.jp/","http://www.yahoo.co.jp/"] という2つの要素を持つ配列があるとして、 これを.split(/\//)を使用して分割しuriの3番目の要素に当たるhost名を別の配列 array2["www.google.co.jp","www.yahoo.co.jp"] という感じに部分複製したいのですがどのようにすればいいのでしょうか?

    • ベストアンサー
    • Ruby
  • 1次元配列のソート方法

    配列のソートメソッドについて質問させていただきます。 VB.NET初心者なので日本語がおかしいかもしれませんが、宜しくお願いいたします。 データテーブルが格納されている配列があり、 その配列をソートしたいと思っています。 データテーブルの中に「NO」と「ID」というフィールドがあります。 NOで昇順し、NOが同じだったらIDの昇順でソートといったことがしたいのですが、 条件によっては上手くいきません。 よろしければ、教えていただけないでしょうか? また、もっと効率の良い方法とかありましたら、具体的はソース等教えていただけないでしょうか? 宜しくお願いいたします。 [例] workDT() ← 元のデータテーブル配列 Dim Datatable(workDt.Rows.Count-1) As DataTable ← ソート後のデータテーブル配列 Dim tmpDatatable(workDT.Rows.Count-1) As DataTable ← 途中で使うデータテーブル配列 Dim NO(workDT.Rows.Count-1) As Integer ← 元のデータテーブル配列の各「NO」フィールドを格納する配列 Dim ID(workDT.Rows.Count-1) As String ← 途中で使うデータテーブル配列の各「ID」フィールドを格納する配列 Dim Index(workDT.Rows.Count-1) As Integer ← インデックスに使用 ' IDでソート For i = 0 To workDt.Length - 1 ID(i) = workDt(i).Rows(0).Item("ID") Index(i) = i Next ' 配列をIDでソート Array.Sort(ID, Index) ' ソート後配列をテンプ配列に格納 For i = 0 To workDt.Length - 1 tmpDatatable(i) = workDt(Index(i)).Copy Next ' NOでソート For i = 0 To tmpDatatable.Length - 1 NO(i) = tmpDatatable(i).Rows(0).Item("NO") Index(i) = i Next ' 配列をNOでソート Array.Sort(NO, Index) ' ソート後配列を格納 For i = 0 To tmpDatatable.Length - 1 Datatable(i) = tmpDatatable(Index(i)).Copy Next これで各配列を初期化します。 workDTに5つのデータテーブルが入っていて workDT(0):ID=3、NO=1 workDT(0):ID=1、NO=5 workDT(0):ID=2、NO=5 workDT(0):ID=4、NO=5 workDT(0):ID=5、NO=7 (IDは重複不可設定、NOは重複可設定です。) とした場合、NOのソートのところで変な順番になってしまいます。 Array.Sort(NO, Index) このメソッドは同じ値だった場合、何を優先してソートしているのでしょうか? 環境はWindowsXPSP3とVB2005です。

  • 無名配列をsplitする方法

    データベースから吐き出した数百行のデータがあります。それを無名配列に入れているのですが、 1)1列目の一行目を変数に格納したい。 2)7行目を全部足して、その結果を変数に格納したい。 コードが会社にあるため、十分に説明できなければすみません。 一部分でもヒントがございましたら教えてくださいまし。 eval column bind{} #dbh 処理完了 while sth hashref_array() { #無名配列へ格納 my $z = $a->[3]; #一行前のデータを使用 my $b = $z / 12; my $c = $a->[4];  my $d = ($z / $c)**0.38888888; $a=[$x, $b, $c, $d, $e, $f, $g]; }

  • ruby 配列の中の文字列を全部数値にしたい

    array=%w(1 2 3 4) のような文字列の配列があるとします。 これを数値の配列にしたいです。 以下の様にしてみました。 array=array.inject([]){|a,v| a<< v.to_i } これでも出来ましたが、もっとrubyらしい方法ってあったら教えて下さい。

    • ベストアンサー
    • Ruby
  • 連想配列のソートについて

    調べても分からなかったので質問させてください。 現在アクセスログ集計ツールを作成中です。 決められたurlのページにアクセスがあった時にDB登録し、カウントする単純な仕組みで、ツールの方では日にちを任意で選択してもらいエクセル出力する仕組みです。 質問させていただきたいのが、カウントをするページが例えば4ページあり、そのページ名の接頭を取って「date」「index」「login」「stock」「option」というキーの連想配列を作っています。 array(5) { ["date"]=> array(3) { [0]=> string(10) "2015/02/01" [1]=> string(10) "2015/02/02" [2]=> string(5) "total" } ["Index"]=> array(3) { [0]=> int(2) [1]=> int(4) [2]=> int(6) } ["Login"]=> array(3) { [0]=> int(6) [1]=> int(6) [2]=> int(12) } ["Stock"]=> array(3) { [0]=> int(3) [1]=> int(4) [2]=> int(7) } ["option"]=> array(3) { [0]=> int(2) [1]=> int(1) [2]=> int(3) } } このキーである「index」「login」「stock」「option」の順番が取得するデータによって入れ替わってしまいます。 理想的な順番としては「login」「index」「option」「stock」の順番にソートしたいのですが、調べても分かりませんでした。sort関数はアルファベット順とか、数値順とか決まったルールのソートができるようですが、こちらで意図的に順番を操作する事はできるのでしょうか? もしあれば教えていただきたいです、何卒よろしくお願いいたします。

    • ベストアンサー
    • PHP

専門家に質問してみよう