简体   繁体   中英

Trying to Understand How the sort_by function works in Ruby

I'm going through the tutorial Bastards Book of Ruby and I'm having trouble understanding how the function sort_by works. Here's the exercise:

Exercise: Sort names by last name

Given an array of strings that represent names in "FIRSTNAME LASTNAME" form, use sort_by and split to return an array sorted by last names. For simplicity's sake, assume that each name consists of only two words separated by space (ie only "John Doe" and not "Mary Jo Doe").

names = ["John Smith", "Dan Boone", "Jennifer Jane", "Charles Lindy", "Jennifer Eight", "Rob Roy"]

And here's the solution :

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

However, when I run the code

sorted_names = names.sort_by do |name|
  puts name.split(" ").reverse.join.upcase
end

I get the output:

SMITHJOHN
BOONEDAN
JANEJENNIFER
LINDYCHARLES
EIGHTJENNIFER
ROYROB

which is quite different than the output from puts sorted_names.join('; ')

I thought the method was actually manipulating the data (hence name.split(" ").reverse.join.upcase ) and then saving it to the new array sorted_names . But obviously it's not. So, my question is can someone please explain why this sort_by method is acting this way. I'm relatively new to Ruby and I tried looking through the Ruby docs for an explanation but couldn't find one. I feel I'm not understanding an important concept in Ruby and would appreciate any help or insight.

#sort_by expects you to return a value to sort by. The fact that you have puts where a return should be is causing #sort_by to return nil for each element, which prevents any sorting from taking place.

sort_by is kind of like doing this:

a.map {|item| [f(item), item]}.sort.map {|key, item| item}

That is, the sort_by block is used to calculate a sort-key for each value in the array, and then those keys are sorted, and then those keys are mapped back to the original values.

So what you're seeing are those keys, before they're used to sort. Except as ranksrejoined noted, puts returns nil, so by examining the keys you've broken the function!

Not sure this will help in this case but tap is handy for poking around at things without disturbing the control flow:

sorted_names = names.sort_by do |name|
  name.split(" ").reverse.join.upcase.tap { |str| puts str }
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM