group_by 与 partition
本课属于 Coddy Ruby 学习旅程的“逻辑与流程”单元。第 25 课,共 56 课。
有时,你可能想要拆分集合,而不是筛选集合。两种方法可以满足大多数需求。
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"]}这是一次遍历就能对项目进行分组的最简洁方式。
partition 是二元版本:它会返回一对数组,一个包含块为 true 时的元素,另一个包含其余元素:
evens, odds = [1, 2, 3, 4, 5].partition { |n| n.even? }
puts evens.inspect # [2, 4]
puts odds.inspect # [1, 3, 5]正好有两个分组时使用 partition,可能有多个分组时使用 group_by。
挑战
中等读取一个以逗号分隔的 name:score 条目列表(例如 Alice:88,Bob:42,Charlie:75)。使用 group_by,然后使用 partition 生成一份简短报告。
步骤:
- 将每个条目解析为一个
[name, score]键值对(score 是整数) - 根据键值对中
name的首字母(大写)使用group_by分组 - 对于每个字母组,按字母顺序使用
partition将条目分为及格(score >= 60)和不及格,然后每组打印一行:
<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 与 Reject链式调用 MapReduce / Injectcount、all?、any?、none?group_by 与 partitionsort_by、min_by、max_by回顾:数据管道自己练习: Ruby 在线编译器