试图理解sort_by函数在Ruby中的工作原理

时间:2012-01-23 02:17:27

标签: ruby-on-rails ruby arrays sorting

我正在阅读教程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中的一个重要概念,并且会感谢任何帮助或见解。

3 个答案:

答案 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