FAQ: Create a Histogram - Sorting the Hash

This community-built FAQ covers the “Sorting the Hash” exercise from the lesson “Create a Histogram”.

Paths and Courses
This exercise can be found in the following Codecademy content:

Learn Ruby

FAQs on the exercise Sorting the Hash

There are currently no frequently asked questions associated with this exercise – that’s where you come in! You can contribute to this section by offering your own questions, answers, or clarifications on this exercise. Ask or answer a question by clicking reply (reply) below.

If you’ve had an “aha” moment about the concepts, formatting, syntax, or anything else with this exercise, consider sharing those insights! Teaching others and answering their questions is one of the best ways to learn and stay sharp.

Join the Discussion. Help a fellow learner on their journey.

Ask or answer a question about this exercise by clicking reply (reply) below!

Agree with a comment or answer? Like (like) to up-vote the contribution!

Need broader help or resources? Head here.

Looking for motivation to keep learning? Join our wider discussions.

Learn more about how to use this guide.

Found a bug? Report it!

Have a question about your account or billing? Reach out to our customer support team!

None of the above? Find out where to ask other questions here!

words.each { |word| frequencies[word] += 1 }

I am really confused by this line of code, can someone please explain it to me. I get that you’re iterating over the words array but what does this part do:
frequencies[word] += 1

Any help would be appreciated :slight_smile:

2 Likes

words.each { |word| frequencies[word] += 1 }

I believe all that this line of code is doing is increasing the counter that you initially set at ‘0’ (i.e. frequencies = Hash.new(0)).

As per the instructions on the 5th exercise: “This is why our default is 0 . The first time we find the word, it will have a default value of `` 0 that we can increment by 1`”

1 Like

I’m not sure I understand the solution. Anyone willing to explain it in layman terms?

frequencies = frequencies.sort_by do |word, count|
count
end

frequencies.reverse!

As we enter this phase of the program, frequencies is a hash of words and their frequency. sort_by will return an array of word/count pairs, so no longer a hash. We choose which to sort by, word or count, and get a sorted list by that key. Since the hash is no longer needed, the output of this method is assigned back onto that variable.

2 Likes

hi! i don’t know what’s happening with my code. Anyone willing to explain me?

puts "How are you? "
text=gets.chomp

words=text.split

frequencies=Hash.new(0)

words.each { |word| puts word
frequencies [word] +=1
puts frequencies
}

frequencies=frenquencies.sort_by do |word,count| count end
frequencies.reverse!

Could it be that .split() is a method so must be invoked with ()?

1 Like

thank you!! was actually a syntaxis error in the last line ahah

1 Like

I’m slightly confused as to how the code :

words.each { |word| frequencies[word] += 1 }

knows to increase the word (key’s) value by 1 when it comes across it more than once, instead of simply creating a hash that simply has a key for each and every word, with a value of 1.

Does my question make sense? I would have assumed that we would need some sort of comparison operator or something, to compare the words to the words(keys) that are already in the hash?

Hashes cannot have duplicate keys. If a key is not present it gets inserted with the default value, which is then incremented. When the key exists, its value simply gets incremented.

1 Like

Perfect! Thank you for this answer!

1 Like

Can someone explain the methodology behind

frequencies = frequencies.sort_by do |word,count|
count
end

And are there any other techniques to get the same result?

Not with the same horsepower, afaik.

is able to transform a hash into an array of key-value pairs in their own array.

a = {}
a['word'] = 4
a['phrase'] = 2
a['the'] = 5
a['letter'] = 2
a['and'] = 1
b = a.sort_by do |value, count|
  count
end
puts a
puts b

output

{"word"=>4, "phrase"=>2, "the"=>5, "letter"=>2, "and"=>1}
[["and", 1], ["phrase", 2], ["letter", 2], ["word", 4], ["the", 5]]

To reverse the sort we prepend the variable with a negative sign.

b = a.sort_by do |value, count|
  -count
end
puts b

output

[["the", 5], ["word", 4], ["phrase", 2], ["letter", 2], ["and", 1]]

Bottom line, this is a very powerful method. Any other approach is doubtless going to take more logic.

1 Like

I’m really struggling to understand parts of the code in the exercise:

puts "Enter a phrase you’d like to analyze: "
text = gets.chomp
words = text.split
frequencies = Hash.new(0) - What does the 0 here do or mean?
words.each { |word| frequencies[word] += 1 } - This should give the location of every word and add 1 to it. Correct? Which part is counting the frequencies exactly? I’m confused
frequencies = frequencies.sort_by do |word, count|
count - What does this count mean here exactly? Is it a command or just to create the variable “count” again?
end
frequencies.reverse!
frequencies.each do |word, count|
puts word + " " + count.to_s
end

It means that every new hash will have a default initial value of zero. That is so we can do arithmetic (addition) on the value.

The word is a key of the hash, and the frequency is how many times the word appears in the text.

hash.sort_by() returns an array of arrays, each comprising a key-value pair from the hash. It is no longer a hash, but a sorted array. count is the second positional value in each array, so we are sorting by least to most, unless we reverse the order.

2 Likes

So the temporary variable “count” can also called just “v”?

I ask that cause i’m wondering… my initial try to write this Statement was like the Hint in this Step:

frequencies = frequencies.sort_by { |k, v| v }

But this don’t work… i tested it with an following “puts” Statement:

frequencies.each do |x|
puts x
end

i wrote in the input: one two two

the Result was:
[“two”, 1]
[“one”, 1]

maybe that confuse people in this exercise… Can you explain the Error? “Count” is the second value in the Hash… and we write this in an temporary variable… so how the variable called should be unnecessary in our opinion…

The variable names are arbitrary.

frequencies = frequencies.sort_by {|a, b| b}
frequencies.reverse!
puts frequencies
frequencies.each {|k, v| puts "#{k} #{v}"}

In the above, we could have called, v, count and k, word. It’s only intention is to be sure the reader is not confused.

Enter some text: 
A quick brown fox jumps over the lazy dog then jumps the brown fence
# hash
{"A"=>1, "quick"=>1, "brown"=>2, "fox"=>1, "jumps"=>2, "over"=>1, "the"=>2, "lazy"=>1, "dog"=>1, "then"=>1, "fence"=>1}
# sorted array of key/value pairs
[["the", 2], ["jumps", 2], ["brown", 2], ["fence", 1], ["then", 1], ["dog", 1], ["lazy", 1], ["over", 1], ["fox", 1], ["quick", 1], ["A", 1]]
# iteration output
the 2
jumps 2
brown 2
fence 1
then 1
dog 1
lazy 1
over 1
fox 1
quick 1
A 1

Here is a detailed explanation -

frequencies = Hash.new(0)
#This created an empty data structure. If we call on it we get the default value of 0 for anything right now.

frequencies[word] += 1
#This part ‘grabs’ each word from your array and checks if it is present in the data structure you created before. I.e. did you say “cat” before? No? That’s fine! The word “cat” is now stored in “frequencies” structure with a +1 counter. You go onto the same word, rinse and repeat for the array. If words are repeated they are re-assessed within the frequencies variable.

Or to put simply, this is the part that puts your words into the frequencies ‘table’ and counts them.

Hi everyone. I’m very confused by the histogram lesson and I’m hoping someone can help.

Until now, I’ve thought of arrays and hashes as separate things, but suddenly in this lesson they seem to be working together in a way I can’t get my head around.

I’m ok as far as creating the frequencies hash and setting a default value, but after that I can’t explain what’s going on. I can’t grasp at all why we are chopping and changing between hashes and arrays?

I’ve read the replies above, but I still can’t make sense of this lesson. I’d be very grateful if someone could break it down in very plain terms.

Also, in the example code at the beginning of the lesson, (" ") is used after the .split method on text. I accidentally omitted it and it seems to run fine, so I’m confused as to why they have it in the example code?

Thanks.

My code:

Screenshot 2022-11-30 at 15.27.04

Example code from lesson:

Screenshot 2022-11-30 at 13.44.38

Let’s break down what happens after creating the frequencies hash and setting a default value of 0:

words.each { |word| frequencies[word] += 1 }

Here, we iterate over the words array. words was always an array, since it was set to text.split. text was originally a variable holding the user’s input as a string. You can read more about split here.

text.split(" ") and text.split are equivalent, since delimiting by a space is .split’s default value. I think it was shown as text.split(" ") at first to make this behavior more clear to the learner.

Each word is then used as a key in the frequencies hash, incremented by the total number of times it appears in words. The total number becomes the value associated with the key.

For example, if my text input was originally “yes no yes no maybe yes”, the words array would be:

["yes", "no", "yes", "no", "maybe", "yes"]

After words.each { |word| frequencies[word] += 1 } the frequencies hash — originally set to 0 — would then become:

{"yes"=>3, "no"=>2, "maybe"=>1}

The next line of code is:

frequencies = frequencies.sort_by { |word, count| count }

word and count represent the key-value pairs in the frequencies hash; you could call them anything, but labeling them this way makes what is happening in the code more clear. You want to sort by value (the count) in the frequencies hash. After this code, the hash becomes an array because we are assigning the result of sort_by back to frequencies:

[["maybe", 1], ["no", 2], ["yes", 3]]

We then want to reverse this so it will be in highest to lowest order, as the exercise asks for:

frequencies.reverse!

Now frequencies will be the following (still an array):

[["yes", 3], ["no", 2], ["maybe", 1]]

As I mentioned, frequencies is deliberately changed from an array to a hash due to storing the results of sort_by back into frequencies; turning frequencies into an array is only a requirement of the lesson.

frequencies could remain as a hash if you wanted it to in your own program. An example you can try with any input you like; you’ll see that frequencies will remain a hash and be sorted properly:

text = gets.chomp
words = text.split
frequencies = Hash.new(0)
words.each { |word| frequencies[word] += 1 }

sortby_frequencies = frequencies.sort_by { |word, count| count }.reverse
frequencies = Hash[sortby_frequencies]
puts frequencies

However, note also that it is common for arrays and hashes to work together and for you to use one to impact the other in Ruby and the lesson provides a good way to practice this.