Erik Aasland
Erik Aasland

Reputation: 167

Need help understanding a .sort_by block within my Ruby method

I am attempting to improve my coding by working through Code Wars problems and am doing it in a specific manner. First I try working out the code on my own. Failing that I do a few Google searches (Stack Exchange) to troubleshoot. Failing that I unlock the answer to the problem and then thoroughly examine it and articulate the code in writing so I understand the code within the answer. Well, I had to the the latter today.

I understand the lion's share of the code, but I am feeling a bit shaky around my understanding of the code in the fourth line. I have done a bunch of research around the methods used in this code on Rubydocs, but still feel in the dark. Could someone please articulate it part for part for me? I am also looking for any type of advice around my current articulation of the code.


def letter_frequency(text)
  chars = text.downcase.scan(/[a-zA-Z]/).sort
  chars.map { |x| [x, chars.count(x)] }.uniq
  .sort_by { |y| [-y[1], y[0]] }
end
  1. set the "chars" variable to text (the parameter), lowercased, scan and return any single charecter between the range a-z or A-Z, and then sort them lowest to high.

  2. use .map to set a key variable and return all of the charecters inside the submitted array with the total count for the key (x), and then make all charecteds unique with the .uniq method.

  3. Then sort with the given block using the "y" key to return all of the negative/positive numbers and their count within the submitted array.


Thanks a million!

Upvotes: 0

Views: 136

Answers (1)

vikram7
vikram7

Reputation: 495

sort_by does pretty much what it sounds like. It lets you "sort" a hash based on some criteria (that you pass to a block). Since hashes don't really have an order, it returns an array sorted by the criteria you passed in the block:

Consider the following hash (count of the characters in 'hello'):

chars = {"h"=>1, "e"=>1, "l"=>2, "o"=>1}

The key is the character and the value is the count. If we wanted a sorted array of characters based on their count, we could run sort_by on the above hash based on the value like so:

chars.sort_by { |key, value| value }

That would return the following:

[["h", 1], ["e", 1], ["o", 1], ["l", 2]]

If we wanted the most common characters first, we'd sort on -value:

chars.sort_by { |key, value| -value }

Which would return the following:

[["l", 2], ["h", 1], ["e", 1], ["o", 1]]

I've rewritten your method with some tweaks:

def letter_frequency(text)
  count = Hash.new 0
  chars = text.downcase.scan(/[a-zA-Z]/)
  chars.each do |char|
    count[char] += 1
  end
  count.sort_by { |_, value| -value }
end

First, count is the hash that stores the counts of the characters of your text, which we then sort by the count of each character (value). The _ in the sort_by block is a bit of shorthand because we don't use the key of the hash for anything.

Upvotes: 1

Related Questions