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

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

ただいまの
回答率

90.35%

  • Ruby

    8162questions

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

  • ソート

    71questions

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

Rubyでのソート方法

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 751

hasimotoo

score 1

前提・実現したいこと

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>'

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • hasimotoo

    2017/01/06 12:46

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

    キャンセル

  • 退会済みユーザー

    2017/01/06 12:59

    こちらの質問が他のユーザから「やってほしいことだけを記載した丸投げの質問」という指摘を受けました
    「質問を編集する」ボタンから編集を行い、調査したこと・試したことを記入していただくと、回答が得られやすくなります。

  • otn

    2017/01/06 13:04 編集

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

    キャンセル

回答 3

checkベストアンサー

+1

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

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


2は単にソート。

data = []
while line = gets
  line.chomp!
  array = line.split(",") 
  data << array
end


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

# 男性の最高齢
who = 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"を記述して下さい。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

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

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

x.rb

require 'csv'

headers, *data = CSV.read('dummy.csv', headers: false)

p headers    # ['名前', '性別', '年齢', '誕生日', '都道府県']
p data.size  # 5000
p data[0]    # ['細山 勝久', '男', '34', '1982/11/18', '新潟県']

# 男性の最高齢者一覧
p max_old = data.select { |x| x[1] == '男' }.map { |x| x[2].to_i }.max
p data.select { |x| x[1] == '男' && x[2].to_i == max_old }

# 都道府県別の人数
p z = data.group_by { |x| x[4] }.map { |k, v| [k, v.size] }

# 都道府県別の人数の合計
p 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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

#encoding : utf-8
f = File.read("ファイル名").encode("UTF-8").split("\n").map!{|e| e.split("\,")}
ken = []
years = []
f.each do |element|
  ken << element[5]
  years << element[10]
end

ken_list = ken.uniq
ken_count = []
ken_sort = []
ken_list.each do |e|
  ken_count << [e, ken.count(e)]
  ken_sort << ken.count(e)
end

ken_sort
ken_sort_new = ken_sort.sort.reverse

rank = 0
loop{
  ee = ken_sort_new[rank]
  name = ken_count[ken_sort.index(ee)][0]
  num = ken_count[ken_sort.index(ee)][1]
  puts "#{rank + 1}\s#{name + num.to_s}\s人"
  rank += 1
  if rank == 5 || rank > ken_list.length - 1 then
    break
  end
}
years_sort = years.sort
man = []
woman = []
years_sort.each do |y|
  name = f[years.index(y)][0]
  year = f[years.index(y)][10]
  sex = f[years.index(y)][2]
  if sex == "男" then
    man << [name + year + sex]
  elsif sex == "女" then
    woman << [name + year + sex]
  end
end
puts man[0]
puts woman[0]


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

#encoding : utf-8
f = File.read("ファイル名").encode("UTF-8").split("\n").map!{|e| e.split("\,")}
ken = []
years = []
f.each do |element|
  ken << element[5]
  years << element[10]
end

ken_list = ken.uniq
ken_count = []
ken_list.each do |e|
  ken_count << [ken.count(e), e]
end
ken_count.sort!.reverse!

num = 0
loop{
  rank = num + 1
  puts rank.to_s + ken_count[num][1] + ken_count[num][0].to_s + "人"
  num += 1
  if num == 5 || num > ken_count.length - 1 then
    break
  end
}
years_sort = years.sort
man = []
woman = []
years_sort.each do |y|
  name = f[years.index(y)][0]
  year = f[years.index(y)][10]
  sex = f[years.index(y)][2]
  if sex == "男" then
    man << [name + year + sex]
  elsif sex == "女" then
    woman << [name + year + sex]
  end
end
puts man[0]
puts woman[0]


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

#encoding : utf-8
=begin
[1]について、私は単純にそれぞれの県の人数を数えて人数の多い順に並び替えることにしました。
[2]については、生年月日順に氏名を並び替えたのち、男女で分けて男の先頭と女の先頭を
表示することにしました。
=end
f = File.read("ファイル名.csv").encode("UTF-8").split("\n").map{|e| e.split("\,")}
=begin
#1:データの入ったメモ帳を読み込みます。手を加えやすいようにUTF-8にエンコードします。
  このファイルは1行で一つのまとまりになっているのでいったん改行で分割<split("\n")>
   します。このままだと1行がすべてくっついているので、くっついている1行を対象にカンマで分割
   <split("\,")>します。
=end
ken = [] #2:県名を入れる配列を作ります。
years = [] #3:氏名、生年月日、性別だけを1つにまとめた情報を入れる配列を作ります。
f.each do |element|
  ken << element[4]
  years << [element[3], element[0], element[2]]
end
=begin
#4:f(最初に読み込んだファイル)の中身(例:[佐藤 太郎,サトウ タロウ,男,,887-4155,宮城県,xx市,xx,3-50-5,xxマンション307,1982/06/09,O ]を
  順番にelementに入れて処理を行います。
  処理の内容は2つあって、1つは県名をとってkenに入れるもの、もう1つは生年月日、氏名、性別をとってyearsに入れるものです。
=end

ken_list = ken.uniq #5:#4によって今、kenには県名が入っています。このkenから重複した県名を削除した新しい配列ken_listを作ります。
ken_count = [] #6:数えた県名の数(=その県名が含まれたデータの数)を入れておく配列を作ります。
ken_list.each do |e| #7:ken_listの中身(例:[沖縄県, 宮城県, 広島県])を順番にeに入れます。
  ken_count << [ken.count(e), e]
end
=begin
#8:重複ありで県名が入っているkenを対象にe(個別の県名)の個数を調べます。その個数とe(個別の県名)を
   ken_countに入れます。
=end
ken_count.sort!.reverse!
=begin
#9:ken_countをsortします。sortをすると数字の小さい順に並べ替えられます。
   並び替えられた結果をreverseすることで数字を大きい順に並び替えることができます。
=end
years.sort!
=begin
#10:ついでに氏名、生年月日、性別が入っているyearsもsortをします。
    こちらは生年月日の古い順(=数字が小さい順)なのでsortだけで大丈夫です。
=end
num = 0 #11:県名と人数を数字の大きい順に5つ表示します。表示にはloopを使います。
loop{
  rank = num + 1 #12:順位に使う数字です。numは0から始まるので1を足さないと順位が1位からになりません。
  puts rank.to_s + "\s" + ken_count[num][1] + ken_count[num][0].to_s + "人"
  #13:rank.to_sでrankを文字にします。そうしないと文字と+できません。初めにファイルをUTF-8にエンコード
  #   しておかないとこの辺でエラーが出ると思います。画面に表示したときに見やすいように、文字にしたrankの後ろに
  #   スペースを入れます。その次にken_count(配列)のnum番目にある要素(配列)の1番目の要素=県名と
  #   ken_count(配列)のnum番目にある要素(配列)の0番目の要素=人数を文字にしたものを足しています。
  num += 1 #14:numに1を足します。そうしないと2位以降が表示されなくなります。
  if num == 5 || num > ken_count.length - 1 then
    #15:loopを抜ける処理を書いています。このloopはnum==5(numは0から始まっているので順位では6位)
    #   になるか、numがken_countの要素の数を超える(県名が5よりも少なかった場合用)と終了します。
    break
  end
}

man = [] #16:男性を入れておく配列を作ります。
woman = [] #17:女性を入れておく配列を作ります。
years.each do |date|
  #18:氏名、生年月日、性別が入ったyearsの要素(例[[氏名1, xxxx/xx/xx, 男], [氏名2, xxxx/xx/xx, 女]]を
  #   順番にdateに入れます。
  if date[2] == "男" then #19:dateの3番目(配列の要素は0から数える)の要素が男なら
    man << date #20:manにdateを入れます
  elsif date[2] == "女" then #21:dateの3番目(配列の要素は0から数える)の要素が女なら
    woman << date #20:womanにdateを入れます
  end
end
puts "-------------------------------------------" #21:少しでも見やすくなるように[1]で出した県名と人数ランキングの下に線を引きます。
if man[0] != nil then #22:manの中身が空かどうかで処理を分けます。
  puts "男性:" + man[0][1] + man[0][0]
  #23:空ではない場合は、男性か女性か分かりやすいように性別を表示することにして
  #   manの先頭の要素(配列)の2番目の要素(氏名)とmanの先頭の要素(配列)
  #   の1番目の要素(生年月日)を表示します。
else
  puts "男性:該当者なし"
  #24:空の場合は分かりやすいように"男性:該当者なし"と表示することにします。
end
if woman[0] != nil then #25:manの中身が空かどうかで処理を分けます。
  puts "女性:" + woman[0][1] + woman[0][0]
  #26:空ではない場合は、男性か女性か分かりやすいように性別を表示することにして
  #   womanの先頭の要素(配列)の2番目の要素(氏名)とwomanの先頭の要素(配列)
  #   の1番目の要素(生年月日)を表示します。
else
  puts "女性:該当者なし"
  #27:空の場合は分かりやすいように"女性:該当者なし"と表示することにします。
end
実行結果例
1 東京都4802 大阪府3693 神奈川県3184 愛知県2955 埼玉県281人
-------------------------------------------
男性:上山 勤2016/1/10
女性:中沢 由宇2016/1/10


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

#encoding : utf-8
f = File.read("データ2.txt").encode("UTF-8").split("\n").map{|e| e.split("\,")}
f.shift
puts f.map{|y| [y[3], y[0], y[2]]}.sort.select{|g| g[2] == "女"}.map{|word| word[1] + word[0] + word[2]}[0]
puts f.map{|y| [y[3], y[0], y[2]]}.sort.select{|g| g[2] == "男"}.map{|word| word[1] + word[0] + word[2]}[0]
puts "---------------------------------------"
f.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による推測などを試した

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

同じタグがついた質問を見る

  • Ruby

    8162questions

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

  • ソート

    71questions

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