Menu
CoddyTech

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。

challenge icon

挑战

中等

读取一个以逗号分隔的 name:score 条目列表(例如 Alice:88,Bob:42,Charlie:75)。使用 group_by,然后使用 partition 生成一份简短报告。

步骤:

  1. 将每个条目解析为一个 [name, score] 键值对(score 是整数)
  2. 根据键值对中 name 的首字母(大写)使用 group_by 分组
  3. 对于每个字母组,按字母顺序使用 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=...'
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

逻辑与流程中的所有课

自己练习: Ruby 在线编译器