我正在阅读教程Bastards Book of Ruby,但我无法理解函数sort_by
的工作原理。这是练习:
练习:按姓氏对名称进行排序
给定一个表示“FIRSTNAME LASTNAME”形式的名称的字符串数组,使用sort_by和split返回按姓氏排序的数组。为简单起见,假设每个名称只包含两个用空格分隔的单词(即只有“John Doe”而不是“Mary Jo Doe”)。
names = ["John Smith", "Dan Boone", "Jennifer Jane", "Charles Lindy", "Jennifer Eight", "Rob Roy"]
这是解决方案:
names = ["John Smith", "Dan Boone", "Jennifer Jane", "Charles Lindy", "Jennifer Eight", "Rob Roy"]
sorted_names = names.sort_by do |name|
name.split(" ").reverse.join.upcase
end
puts sorted_names.join('; ')
# output=> Dan Boone; Jennifer Eight; Jennifer Jane; Charles Lindy; Rob Roy; John Smith
但是,当我运行代码时
sorted_names = names.sort_by do |name|
puts name.split(" ").reverse.join.upcase
end
我得到了输出:
SMITHJOHN
BOONEDAN
JANEJENNIFER
LINDYCHARLES
EIGHTJENNIFER
ROYROB
与puts sorted_names.join('; ')
我认为该方法实际上是在操纵数据(因此name.split(" ").reverse.join.upcase
),然后将其保存到新数组sorted_names
。但显然不是。所以,我的问题是有人可以解释为什么这个sort_by
方法就是这样做的。我对Ruby比较陌生,我尝试通过Ruby docs查看解释但找不到。我觉得我不理解Ruby中的一个重要概念,并且会感谢任何帮助或见解。
答案 0 :(得分:4)
#sort_by
希望您返回一个值以进行排序。您puts
return
所在的#sort_by
导致nil
为每个元素返回{{1}}这一事实,这会阻止任何排序。
答案 1 :(得分:4)
sort_by有点像这样做:
a.map {|item| [f(item), item]}.sort.map {|key, item| item}
也就是说,sort_by块用于计算数组中每个值的排序键,然后对这些键进行排序,然后将这些键映射回原始值。
所以你看到的是那些键,在他们习惯排序之前。除了注意到rankrejoined,puts返回nil,所以通过检查你已经破坏了函数的键!
答案 2 :(得分:0)
在这种情况下,不确定这会有所帮助,但tap
可以在不影响控制流程的情况下进行操作:
sorted_names = names.sort_by do |name|
name.split(" ").reverse.join.upcase.tap { |str| puts str }
end