dポイントプレゼントキャンペーン実施中!

お世話になります。
表題のとおり、言語[RUBY]を用いて、特定列をキーとした並び替えを行う際の記述を知りたいです。
現在input.txtの中に、スペース区切りのテキストで
id X Y Z
1 8 7 9
2 2 3 6
3 4 5 8
4 3 4 5
以下続く

となっています。Zが小さい方から大きい方に行ごと並び替えて、結果をout.txtに出力してほしいです。
結果として
id X Y Z
4 3 4 5
2 2 3 6
3 4 5 8
1 8 7 9

というイメージです。
現在は表計算ソフトでやってはいるのですが、量が多いと動かなくなってしまいまして。

input.txtは時にはスペース区切りのテキストで
id X,Y Z
1 8,7 9
2 2,3 6
3 4,5 8
4 3,4 5
以下続く

のようにX,Yが一塊になっている場合もあります。その時にはX,YのXの方を基準に並び替えたいです。
イメージは
id X,Y Z
2 2,3 6
4 3,4 5
3 4,5 8
1 8,7 9

です。すみませんがやり方をご存知の方、お助け願えませんでしょうか。よろしくお願いします。

質問者からの補足コメント

  • input.txtは時にはスペース区切りのテキストで
    id X,Y Z
    1 8,7 9 ここ
    2 2,3 6
    3 4,5 8
    4 3,4 5
    5 8,7 8 ここ
    6 8,7 10 ここ
    7 8,7 3 ここ
    以下続く

    となっているようなときに、「ここ」という文字があるところはX,Yが同じでZの値が異なっています。その時に、
    id X,Y Z
    2 2,3 6
    4 3,4 5
    3 4,5 8
    7 8,7 3 ここ
    5 8,7 8 ここ
    1 8,7 9 ここ
    6 8,7 10 ここ
    以下続く

    見たく、X,YのXを基準に並び替えつつ。かつZの小さい方から大きい方へという事も可能でしょうか?

      補足日時:2017/11/20 11:09

A 回答 (2件)

以下で如何でしょうか


1.双方とも1行目の文字コード指定は環境に合わせて書き換えて下さい。
 下記はWindows環境です。
2.扱う数値が実数の場合は、「to_i」を「to_f」へ変更してください。
 id列の数値も実数になってしみますが……

前者
-----
#coding: cp932

key_col = 3 # idを第0列として、Zは第3列

is_header = true
header = ""
data = []

File.foreach("input.txt") do |line|
line.chomp!
if is_header
header = line
is_header = false
else
data.push(line.split(" "))
end
end
data.sort!{|a,b| a[key_col].to_i - b[key_col].to_i}
File.open("out.txt","w") do |f|
f.puts header
data.each do |e|
f.puts e.join(" ")
end
end
-----

後者
-----
#coding: cp932

is_header = true
header = ""
data = []

File.foreach("input.txt") do |line|
line.chomp!
if is_header
header = line
is_header = false
else
data.push(line.split(","))
end
end
data.sort!{|a,b| a[0].split(" ")[-1].to_i - b[0].split(" ")[-1].to_i}
File.open("out.txt","w") do |f|
f.puts header
data.each do |e|
f.puts e.join(",")
end
end
-----
    • good
    • 0
この回答へのお礼

siffon9様
お返事遅れてすみません。
たった今出先より戻って実行してみました。

ありがとうございます。表計算ソフトのフリーズにおびえなくて済みそうです。
一つお聞きしたいです。
「data.sort!」の部分でデータを並びなおせという事はなんとなくわかるのですが、小さい方から大きい方へ並びなおせというのは、どこで制御しているのでしょうか?

お礼日時:2017/11/20 10:06

> X,YのXを基準に並び替えつつ。

かつZの小さい方から大きい方へという事も可能でしょうか?

Z列、Y列、X列の順にソートをするようにしてみました。
これで如何でしょう?

#coding: cp932

is_header = true
header = ""
data = []

# データ読み込み
File.foreach("input.txt") do |line|
line.chomp!
if is_header
header = line
is_header = false
else
data.push line
end
end

# Z列ソート
data.sort_by!{|v| v.split(" ")[-1].to_i}
# Y列安定ソート
data.sort_by!.with_index{|v,index| [v.split(",")[1].split(" ")[0].to_i, index]}
# X列安定ソート
data.sort_by!.with_index{|v,index| [v.split(",")[0].split(" ")[-1].to_i, index]}

# ソート済みデータ出力
File.open("out.txt","w") do |f|
f.puts header
data.each{|e| f.puts e}
end
    • good
    • 0
この回答へのお礼

ありがとうございます。
欲しいデータが手に入りました。
そうか、Xソートの前にYソートやらないとぐちゃぐちゃになっちゃうのですか。
安定ソートという言葉自体を知らず、調べて、こんなのがあるんだと思いました。
カンマ区切りとスペース区切りが混在していても、もとの列を維持したままソートできるのはすごいです。
なんだか、魔術みたいです。

勉強不足過ぎました。ソースを見ながら動きも確認してみます。

お礼日時:2017/11/21 09:40

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!