group_by と partition
CoddyのRubyジャーニー「ロジックとフロー」セクションの一部。レッスン 25/56。
コレクションをフィルタリングするのではなく、分割したい場合があります。2つのメソッドでほとんどのケースをカバーできます。
group_by はブロックを受け取り、ハッシュを返します。ブロックの個々のユニークな戻り値がキーとなり、そのキーにはその結果を生成した要素の配列がマッピングされます:
words = ["hi", "hello", "yo", "hey", "bonjour"]
by_length = words.group_by { |w| w.length }
puts by_length.inspect
# {2=>["hi", "yo"], 5=>["hello"], 3=>["hey"], 7=>["bonjour"]}1回のパスで項目を分類する最もクリーンな方法です。
partition はバイナリバージョンです。ブロックが真であった要素の配列と、それ以外の要素の配列のペアを返します:
evens, odds = [1, 2, 3, 4, 5].partition { |n| n.even? }
puts evens.inspect # [2, 4]
puts odds.inspect # [1, 3, 5]バケットが正確に2つある場合は partition を、多数存在する可能性がある場合は group_by を使用します。
チャレンジ
中級カンマ区切りの name:score エントリのリスト(例: Alice:88,Bob:42,Charlie:75)を読み込みます。group_by とそれに続く partition を使用して小さなレポートを出力してください。
手順:
- 各エントリを
[name, score]のペア(scoreは整数)にパースします nameの最初のエントリの文字(大文字)でgroup_byします- 各文字のグループについて、アルファベット順に、エントリを合格(
score >= 60)と不合格にpartitionし、グループごとに1行出力します:
<LETTER>: pass=<names_passing_joined_by_comma> fail=<names_failing_joined_by_comma>各グループ内では、名前は元の順序で表示されます。一方の側に名前がない場合は、空のままにします(例: fail=)。
入力が Alice:88,Adam:42,Bob:75,Beth:55,Cara:90 の場合、出力は次のようになります:
A: pass=Alice fail=Adam
B: pass=Bob fail=Beth
C: pass=Cara fail=自分で試してみよう
entries = gets.chomp.split(",").map do |s|
name, score = s.split(":")
[name, score.to_i]
end
# TODO: 先頭文字(大文字)でグループ化し、各グループを score >= 60 で分割し、
# アルファベット順に 'X: pass=... fail=...' を出力
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
ロジックとフローのすべてのレッスン
5Enumerable の強力な機能
Select と RejectMap のメソッドチェーンReduce / Injectcount, all?, any?, none?group_by と partitionsort_by, min_by, max_byまとめ:データパイプライン自分で練習してみよう: Rubyオンラインコンパイラ