質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

ソート

複数のデータを、順序性に従って並べ替えること。 データ処理を行う際に頻繁に用いられ、多くのアルゴリズムが存在します。速度、容量、複雑さなどに違いがあり、高速性に特化したものにクイックソートがあります。

Q&A

解決済

3回答

2313閲覧

Rubyでのソート方法

hasimotoo

総合スコア7

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

ソート

複数のデータを、順序性に従って並べ替えること。 データ処理を行う際に頻繁に用いられ、多くのアルゴリズムが存在します。速度、容量、複雑さなどに違いがあり、高速性に特化したものにクイックソートがあります。

0グッド

0クリップ

投稿2017/01/06 02:01

編集2017/01/09 12:26

###前提・実現したいこと
Rubyで下記のような情報がたくさん入ったメモ帳を読み込み、

二つのプログラムを作成したいのですが、初心者なのでどのように書けば良いのかお詳しい方是非教えて頂けると助かります。よろしくお願いします。

###補足情報(言語/FW/ツール等のバージョンなど)
・1/9更新
様々な回答本当にありがとうございます。
皆様の回答を参考に作成し、実行したところ次のようなエラーが表示され、上手くいきません。自分なりに調べて解決しようとしたのですが、どうにもならずお手上げです。もしお分かりでしたら回答をよろしくお願いします。
度々申し訳ありません。

C:/Ruby23/lib/ruby/2.3.0/csv.rb:1811:in `sub!': invalid byte sequence in Windows-31J (ArgumentError) from C:/Ruby23/lib/ruby/2.3.0/csv.rb:1811:in `block in shift' from C:/Ruby23/lib/ruby/2.3.0/csv.rb:1805:in `loop' from C:/Ruby23/lib/ruby/2.3.0/csv.rb:1805:in `shift' from C:/Ruby23/lib/ruby/2.3.0/csv.rb:1747:in `each' from C:/Ruby23/lib/ruby/2.3.0/csv.rb:1761:in `to_a' from C:/Ruby23/lib/ruby/2.3.0/csv.rb:1761:in `read' from C:/Ruby23/lib/ruby/2.3.0/csv.rb:1307:in `parse fromC:/Users/users/Desktop/Programing/web/test1.rb:10:in `<main>'

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hasimotoo

2017/01/06 02:58

やってほしいことだけを記載した丸投げの質問になってしまっていることは承知しているのですが、
hasimotoo

2017/01/06 03:04

自分なりに考えたのですが、どうにもならず質問をさせていただきました。やってほしいことだけを記載した丸投げの質問になってしまっていることに関してはどうかお許しください。
otn

2017/01/06 03:38

「Ruby 集計」「Ruby ソート」でぐぐったりはしてないのですか?
hasimotoo

2017/01/06 03:46

検索してみたのですが、恥ずかしながらあまり理解することが出来ませんでした…
otn

2017/01/06 04:26 編集

Rubyを学ぶつもりがないのなら、1は、Excelでピボットテーブル機能を使えば一発です。一応、回答しておきます。
guest

回答3

0

データ量が 100 万件レベルになるなら、Database の利用を検討すべきと思います。
ここでは、データをすべてメモリーに読み込んで処理してみました。

csv データは、
なんちゃって個人情報 http://kazina.com/dummy/
を利用して、ダミーデータ 5000 件を作成し、プログラムをはしらせてみました。

x.rb

ruby

1require 'csv' 2 3headers, *data = CSV.read('dummy.csv', headers: false) 4 5p headers # ['名前', '性別', '年齢', '誕生日', '都道府県'] 6p data.size # 5000 7p data[0] # ['細山 勝久', '男', '34', '1982/11/18', '新潟県'] 8 9# 男性の最高齢者一覧 10p max_old = data.select { |x| x[1] == '男' }.map { |x| x[2].to_i }.max 11p data.select { |x| x[1] == '男' && x[2].to_i == max_old } 12 13# 都道府県別の人数 14p z = data.group_by { |x| x[4] }.map { |k, v| [k, v.size] } 15 16# 都道府県別の人数の合計 17p z.inject(0) { |acc, elem| acc += elem[1] }

実行結果例

$ ruby x.rb ["名前", "性別", "年齢", "誕生日", "都道府県"] 5000 ["細山 勝久", "男", "34", "1982/11/18", "新潟県"] 100 [["加藤 慶太", "男", "100", "1916/1/24", "神奈川県"], ["野田 幸平", "男", "100", "1916/4/12", "兵庫県"], ["今井 竜也", "男", "100", "1916/7/31", "奈良県"], ["佐々木 染五郎", "男", "100", "1916/9/27", "沖縄県"], ["田島 慶太", "男", "100", "1916/9/3", "宮城県"], ["亀井 栄一", "男", "100", "1916/7/21", "千葉県"], ["浅沼 雅彦", "男", "100", "1916/2/23", "大阪府"], ["砂川 聡", "男", "100", "1916/6/4", "愛知県"], ["小日向 雅功", "男", "100", "1916/12/13", "群馬県"], ["中原 サンタマリア", "男", "100", "1916/12/25", "愛知県"], ["西岡 陽介", "男", "100", "1916/6/24", "大阪府"], ["阿久津 寛治", "男", "100", "1916/4/19", "埼玉県"], ["上杉 勇介", "男", "100", "1916/1/30", "北海道"], ["仲村 たかお", "男", "100", "1916/8/4", "東京都"], ["前田 敏和", "男", "100", "1916/7/23", "奈良県"], ["朝倉 豊", "男", "100", "1916/11/15", "埼玉県"], ["松尾 三郎", "男", "100", "1916/2/8", "千葉県"], ["蒼井 和之", "男", "100", "1916/6/12", "青森県"], ["秋葉 洋", "男", "100", "1916/6/23", "山形県"], ["大城 守", "男", "100", "1916/7/25", "神奈川県"], ["平田 守", "男", "100", "1916/1/15", "大阪府"], ["石丸 竜也", "男", "100", "1916/10/22", "埼玉県"], ["大沼 隆之介", "男", "100", "1916/5/3", "三重県"], ["益岡 浩介", "男", "100", "1916/11/8", "兵庫県"], ["池畑 真吾", "男", "100", "1916/10/1", "茨城県"], ["小出 草太", "男", "100", "1916/2/17", "北海道"], ["浅井 人志", "男", "100", "1916/10/21", "京都府"], ["池田 マサカズ", "男", "100", "1916/9/11", "東京都"], ["大竹 ジローラモ", "男", "100", "1916/12/27", "神奈川県"], ["角谷 薫", "男", "100", "1916/7/27", "千葉県"], ["久保 哲平", "男", "100", "1916/3/28", "長崎県"], ["藤村 まさし", "男", "100", "1916/8/18", "山口県"], ["岩佐 建", "男", "100", "1916/8/9", "福島県"], ["下田 優", "男", "100", "1916/8/27", "千葉県"], ["小林 基祐", "男", "100", "1916/5/8", "北海道"]] [["新潟県", 101], ["山形県", 46], ["兵庫県", 250], ["京都府", 107], ["佐賀県", 24], ["東京都", 505], ["茨城県", 109], ["福岡県", 212], ["福島県", 78], ["秋田県", 39], ["熊本県", 79], ["和歌山県", 40], ["青森県", 56], ["千葉県", 244], ["山口県", 63], ["北海道", 232], ["高知県", 27], ["大阪府", 346], ["滋賀県", 51], ["埼玉県", 297], ["三重県", 90], ["鹿児島県", 73], ["山梨県", 41], ["愛知県", 277], ["神奈川県", 325], ["広島県", 118], ["岐阜県", 78], ["岩手県", 48], ["宮崎県", 51], ["岡山県", 75], ["福井県", 29], ["富山県", 39], ["石川県", 51], ["愛媛県", 65], ["長崎県", 55], ["長野県", 77], ["宮城県", 88], ["大分県", 42], ["栃木県", 74], ["静岡県", 146], ["奈良県", 44], ["島根県", 30], ["群馬県", 63], ["沖縄県", 41], ["香川県", 30], ["鳥取県", 12], ["徳島県", 32]] 5000

投稿2017/01/07 05:30

katoy

総合スコア22324

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

1の集計は、いろいろ方法がありますが、入門者にわかりやすいものとしてはこうでしょうか。

Ruby

1# 最初に集計表を作る 2shukei = Hash.new(0) 3~~~~~ 4# 各行に対してカウントアップを繰り返す 5 shukei[array[5]] +=1 6~~~~~ 7# 最後に結果を件数でソートして上位5まで取る 8top5 = shukei.sort_by{|k,v| -v}.take(5)

2は単にソート。

Ruby

1data = [] 2while line = gets 3 line.chomp! 4 array = line.split(",") 5 data << array 6end

と、dataに全員分入れておいて、

Ruby

1# 男性の最高齢 2who = data.find_all{|x| x[2]=="男"}.sort_by{|x| x[10]}.first

#補足への回答

invalid byte sequence in Windows-31J (ArgumentError)

おそらく、Ruby起動オプションまたは環境変数RUBYOPTで、外部エンコーディングにWindows-31J(いわゆるシフトJIS)が指定されているのに、実際のCSVファイルの文字コードがシフトJISでないと言うことです。
UTF-8なのであれば、
Encoding.default_external = "UTF-8"を記述して下さい。

投稿2017/01/06 04:21

編集2017/01/09 01:55
otn

総合スコア84529

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

Ruby

1#encoding : utf-8 2f = File.read("ファイル名").encode("UTF-8").split("\n").map!{|e| e.split("\,")} 3ken = [] 4years = [] 5f.each do |element| 6 ken << element[5] 7 years << element[10] 8end 9 10ken_list = ken.uniq 11ken_count = [] 12ken_sort = [] 13ken_list.each do |e| 14 ken_count << [e, ken.count(e)] 15 ken_sort << ken.count(e) 16end 17 18ken_sort 19ken_sort_new = ken_sort.sort.reverse 20 21rank = 0 22loop{ 23 ee = ken_sort_new[rank] 24 name = ken_count[ken_sort.index(ee)][0] 25 num = ken_count[ken_sort.index(ee)][1] 26 puts "#{rank + 1}\s#{name + num.to_s}\s人" 27 rank += 1 28 if rank == 5 || rank > ken_list.length - 1 then 29 break 30 end 31} 32years_sort = years.sort 33man = [] 34woman = [] 35years_sort.each do |y| 36 name = f[years.index(y)][0] 37 year = f[years.index(y)][10] 38 sex = f[years.index(y)][2] 39 if sex == "男" then 40 man << [name + year + sex] 41 elsif sex == "女" then 42 woman << [name + year + sex] 43 end 44end 45puts man[0] 46puts woman[0]

全く詳しくないですが考えてみました。
私はデータを持っていないので質問の最初に書いてある例を参考にして作りました。
もしかしなくても意図した動きをしない可能性があります。
同じ人数になった場合はどれか一つしか表示されません。
2017/01/06追記
2017/01/07追記
2017/01/07追記
2017/01/09追記

Ruby

1#encoding : utf-8 2f = File.read("ファイル名").encode("UTF-8").split("\n").map!{|e| e.split("\,")} 3ken = [] 4years = [] 5f.each do |element| 6 ken << element[5] 7 years << element[10] 8end 9 10ken_list = ken.uniq 11ken_count = [] 12ken_list.each do |e| 13 ken_count << [ken.count(e), e] 14end 15ken_count.sort!.reverse! 16 17num = 0 18loop{ 19 rank = num + 1 20 puts rank.to_s + ken_count[num][1] + ken_count[num][0].to_s + "人" 21 num += 1 22 if num == 5 || num > ken_count.length - 1 then 23 break 24 end 25} 26years_sort = years.sort 27man = [] 28woman = [] 29years_sort.each do |y| 30 name = f[years.index(y)][0] 31 year = f[years.index(y)][10] 32 sex = f[years.index(y)][2] 33 if sex == "男" then 34 man << [name + year + sex] 35 elsif sex == "女" then 36 woman << [name + year + sex] 37 end 38end 39puts man[0] 40puts woman[0]

同じ人数でも表示されるようになりました。

Ruby

1#encoding : utf-8 2=begin 3[1]について、私は単純にそれぞれの県の人数を数えて人数の多い順に並び替えることにしました。 4[2]については、生年月日順に氏名を並び替えたのち、男女で分けて男の先頭と女の先頭を 5表示することにしました。 6=end 7f = File.read("ファイル名.csv").encode("UTF-8").split("\n").map{|e| e.split("\,")} 8=begin 9#1:データの入ったメモ帳を読み込みます。手を加えやすいようにUTF-8にエンコードします。 10  このファイルは1行で一つのまとまりになっているのでいったん改行で分割<split("\n")> 11 します。このままだと1行がすべてくっついているので、くっついている1行を対象にカンマで分割 12 <split("\,")>します。 13=end 14ken = [] #2:県名を入れる配列を作ります。 15years = [] #3:氏名、生年月日、性別だけを1つにまとめた情報を入れる配列を作ります。 16f.each do |element| 17 ken << element[4] 18 years << [element[3], element[0], element[2]] 19end 20=begin 21#4:f(最初に読み込んだファイル)の中身(例:[佐藤 太郎,サトウ タロウ,男,,887-4155,宮城県,xx市,xx,3-50-5,xxマンション307,1982/06/09,O ]を 22  順番にelementに入れて処理を行います。 23  処理の内容は2つあって、1つは県名をとってkenに入れるもの、もう1つは生年月日、氏名、性別をとってyearsに入れるものです。 24=end 25 26ken_list = ken.uniq #5:#4によって今、kenには県名が入っています。このkenから重複した県名を削除した新しい配列ken_listを作ります。 27ken_count = [] #6:数えた県名の数(=その県名が含まれたデータの数)を入れておく配列を作ります。 28ken_list.each do |e| #7:ken_listの中身(例:[沖縄県, 宮城県, 広島県])を順番にeに入れます。 29 ken_count << [ken.count(e), e] 30end 31=begin 32#8:重複ありで県名が入っているkenを対象にe(個別の県名)の個数を調べます。その個数とe(個別の県名)を 33 ken_countに入れます。 34=end 35ken_count.sort!.reverse! 36=begin 37#9:ken_countをsortします。sortをすると数字の小さい順に並べ替えられます。 38 並び替えられた結果をreverseすることで数字を大きい順に並び替えることができます。 39=end 40years.sort! 41=begin 42#10:ついでに氏名、生年月日、性別が入っているyearsもsortをします。 43 こちらは生年月日の古い順(=数字が小さい順)なのでsortだけで大丈夫です。 44=end 45num = 0 #11:県名と人数を数字の大きい順に5つ表示します。表示にはloopを使います。 46loop{ 47 rank = num + 1 #12:順位に使う数字です。numは0から始まるので1を足さないと順位が1位からになりません。 48 puts rank.to_s + "\s" + ken_count[num][1] + ken_count[num][0].to_s + "人" 49 #13:rank.to_sでrankを文字にします。そうしないと文字と+できません。初めにファイルをUTF-8にエンコード 50 # しておかないとこの辺でエラーが出ると思います。画面に表示したときに見やすいように、文字にしたrankの後ろに 51 # スペースを入れます。その次にken_count(配列)のnum番目にある要素(配列)の1番目の要素=県名と 52 # ken_count(配列)のnum番目にある要素(配列)の0番目の要素=人数を文字にしたものを足しています。 53 num += 1 #14:numに1を足します。そうしないと2位以降が表示されなくなります。 54 if num == 5 || num > ken_count.length - 1 then 55 #15:loopを抜ける処理を書いています。このloopはnum==5(numは0から始まっているので順位では6位) 56 # になるか、numがken_countの要素の数を超える(県名が5よりも少なかった場合用)と終了します。 57 break 58 end 59} 60 61man = [] #16:男性を入れておく配列を作ります。 62woman = [] #17:女性を入れておく配列を作ります。 63years.each do |date| 64 #18:氏名、生年月日、性別が入ったyearsの要素(例[[氏名1, xxxx/xx/xx, 男], [氏名2, xxxx/xx/xx, 女]]を 65 # 順番にdateに入れます。 66 if date[2] == "男" then #19:dateの3番目(配列の要素は0から数える)の要素が男なら 67 man << date #20:manにdateを入れます 68 elsif date[2] == "女" then #21:dateの3番目(配列の要素は0から数える)の要素が女なら 69 woman << date #20:womanにdateを入れます 70 end 71end 72puts "-------------------------------------------" #21:少しでも見やすくなるように[1]で出した県名と人数ランキングの下に線を引きます。 73if man[0] != nil then #22:manの中身が空かどうかで処理を分けます。 74 puts "男性:" + man[0][1] + man[0][0] 75 #23:空ではない場合は、男性か女性か分かりやすいように性別を表示することにして 76 # manの先頭の要素(配列)の2番目の要素(氏名)とmanの先頭の要素(配列) 77 # の1番目の要素(生年月日)を表示します。 78else 79 puts "男性:該当者なし" 80 #24:空の場合は分かりやすいように"男性:該当者なし"と表示することにします。 81end 82if woman[0] != nil then #25:manの中身が空かどうかで処理を分けます。 83 puts "女性:" + woman[0][1] + woman[0][0] 84 #26:空ではない場合は、男性か女性か分かりやすいように性別を表示することにして 85 # womanの先頭の要素(配列)の2番目の要素(氏名)とwomanの先頭の要素(配列) 86 # の1番目の要素(生年月日)を表示します。 87else 88 puts "女性:該当者なし" 89 #27:空の場合は分かりやすいように"女性:該当者なし"と表示することにします。 90end
実行結果例 1 東京都480人 2 大阪府369人 3 神奈川県318人 4 愛知県295人 5 埼玉県281人 ------------------------------------------- 男性:上山 勤2016/1/10 女性:中沢 由宇2016/1/10

ランキング機能を無くしてみました。
katoy様が紹介してくださった「なんちゃって個人情報」を使ってデータを作ってみました。
データの内容は「名前、ふりがな、性別、誕生日、都道府県、電話番号」です。
正確に動いているかどうかは分かりません。

Ruby

1#encoding : utf-8 2f = File.read("データ2.txt").encode("UTF-8").split("\n").map{|e| e.split("\,")} 3f.shift 4puts f.map{|y| [y[3], y[0], y[2]]}.sort.select{|g| g[2] == "女"}.map{|word| word[1] + word[0] + word[2]}[0] 5puts f.map{|y| [y[3], y[0], y[2]]}.sort.select{|g| g[2] == "男"}.map{|word| word[1] + word[0] + word[2]}[0] 6puts "---------------------------------------" 7f.map!{|k| k[4]}.uniq.map{|e|[f.count(e), e]}.sort!.reverse!.map{|word| puts word[1] + word[0].to_s + "人"}
実行結果例 中沢 由宇2016/1/10女 上山 勤2016/1/10男 --------------------------------------- 東京都480人 大阪府369人 神奈川県318人 愛知県295人 埼玉県281人 北海道239人 千葉県227人 福岡県208人 兵庫県184人 静岡県146人 広島県124人 長野県104人 京都府104人 宮城県98人 岐阜県95人 茨城県94人 群馬県90人 栃木県84人 新潟県83人 福島県80人 鹿児島県74人 三重県71人 岩手県70人 熊本県69人 岡山県69人 石川県62人 愛媛県61人 長崎県56人 滋賀県56人 山口県53人 沖縄県52人 大分県52人 奈良県50人 和歌山県48人 青森県47人 秋田県47人 高知県39人 佐賀県39人 香川県38人 山形県38人 山梨県36人 徳島県33人 宮崎県33人 富山県32人 福井県27人 鳥取県24人 島根県21人

###補足について
もしかしたらこちらの記事が参考になるかもしれません。
Ruby文字エンコードに悩まされ、直接指定やnkfによる推測などを試した

投稿2017/01/06 10:15

編集2017/01/09 06:22
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問