先日やった問題で、もっといいやり方を教えてもらったのでやってみる。
3. 配列(リスト)の重複カウント (paizaランク D 相当)
指定された配列(リスト)の定義の中で、同じ要素の数をカウントして、その数を出力してください。
入力される値
なし"HND", "NRT", "KIX", "NGO", "NGO", "NGO", "NGO", "NGO"
を要素に持つ配列(リスト)をプログラムで定義し、使用すること。
ただし、2つ以上同じ要素が出現するのは、1種類の文字列についてだけです。期待する出力
同じ要素の数をカウントして、その数を出力してください。
元々の自分の解答
ary = ["HND", "NRT", "KIX", "NGO", "NGO", "NGO", "NGO", "NGO"] def find_plural(array) plural = array.group_by(&:itself).map do | k, v | [k, v.size] end.to_h.select do | k, v | v > 1 end plural.values end puts find_plural(ary) #=> 5
> 3. 配列(リスト)の重複カウント (paizaランク D 相当)
— バンビちゃん@実際社会不適合者 (@pink_bangbi) 2020年9月30日
ary.tally で一発で解けるやつだ! / Ruby paizaレベルアップ問題集(文字と整数の組のソート2-2) - No Solution for Life - https://t.co/yyffSD7Kr2
tally
!!
前になんかそういうメソッドがあるという話を見かけた気がして探し回ってドキュメントも検索してみたが見つけられなかったやつ。教えてもらってありがたい。
ということで、やり直してみた。
tally
は、レシーバの要素ごとの数を数えて Hash で返してくれるメソッド。
Enumerable#tally (Ruby 2.7.0 リファレンスマニュアル)
array = ['HND', 'NRT', 'KIX', 'NGO', 'NGO', 'NGO', 'NGO', 'NGO'] p array.tally #=> {"HND"=>1, "NRT"=>1, "KIX"=>1, "NGO"=>5}
返ってくるハッシュから、value が 1 より大きいものを探す。
p array.tally.find { |k, v| v > 1 } #=> ["NGO", 5]
該当するものが配列として返ってくるので、インデックスが1
の要素を取り出して出力すれば OK。
解答コード
array = ['HND', 'NRT', 'KIX', 'NGO', 'NGO', 'NGO', 'NGO', 'NGO'] puts array.tally.find { |k, v| v > 1 }[1] #=> 5
dig
今回の問題の場合はこれで正解できたが、find
で該当するものがないケースだと、下のようにエラーになる。
array = ['HND', 'NRT', 'KIX', 'NGO'] puts array.tally.find { |k, v| v > 1 }[1] #=> Main.rb:2:in `<main>': undefined method `[]' for nil:NilClass (NoMethodError)
nil
に[]
というメソッドはない、というエラー。
p array.tally.find { |k, v| v > 1 } #=> nil
find
で該当するものがない場合はnil
が返ってくるため。
dig
というメソッドを使えば、エラーを回避できる。
array = ['HND', 'NRT', 'KIX', 'NGO'] puts array.tally.find { |k, v| v > 1 }&.dig(1)
Array#dig (Ruby 2.7.0 リファレンスマニュアル)
余談:5日前から使っている Scrapbox が快適すぎて、ブログから移行しようと思い始めた(ブログをやめるわけではないけど)。