user11196706
user11196706

Reputation:

Ruby - sorting hashes into descending order by value

I'm trying to solve the following:

"You are given a dictionary/hash/object containing some languages and your test results in the given languages. Return the list of languages where your test score is at least 60, in descending order of the results.

Examples: {"Java" => 10, "Ruby" => 80, "Python" => 65} --> ["Ruby", "Python"]

{"Hindi" => 60, "Dutch" => 93, "Greek" => 71} --> ["Dutch", "Greek", "Hindi"]

{"C++" => 50, "ASM" => 10, "Haskell" => 20} --> []

I am having trouble sorting into descending order by results. Here is what I have so far

def my_languages(results)
array = []
results.each { |a,b| 
results.values.sort.reverse
if b.to_i >= 60
array << a
end
}
return array
end

Not the most elegant solution but I am a complete Ruby newbie (and Stack Overflow newbie too - sorry!) Any advice would be much appreciated!

Upvotes: 0

Views: 386

Answers (3)

wbucko
wbucko

Reputation: 95

To make it faster I would check minimum value when mapping:

hash = {"Hindi" => 60, "Dutch" => 93, "Greek" => 71}

hash.sort.map { |arr| arr[0] if arr[1] >= 60 }.compact

# or imo cleaner

hash.sort.select { |a| a[1] >= 60 }.map(&:first)

Upvotes: 0

Cary Swoveland
Cary Swoveland

Reputation: 110675

h = { "Java" => 10, "Ruby" => 80, "Python" => 65 }

h.select { |_,v| v >= 60 }.
  keys.
  sort_by { |k| -h[k] }
  #=> ["Ruby", "Python"] 

The steps are as follows.

g = h.select { |_,v| v >= 60 }
  #=> {"Ruby"=>80, "Python"=>65} 
a = g.keys
  #=> ["Ruby", "Python"] 
a.sort_by { |k| -h[k] }
  #=> ["Ruby", "Python"] 

If you don't care for -h[k] two alternative follow.

h.select { |_,v| v >= 60 }.
  keys.
  sort_by { |k| h[k] }.
  reverse

and

a = h.select { |_,v| v >= 60 }.
      keys
a.max_by(a.size) { |k| h[k] }

I doubt that one would notice any significant difference in performance among the three.

Enumerable#max_by, min_by, max and min have been permitted to have an optional argument since Ruby v2.2.

Upvotes: 1

Ursus
Ursus

Reputation: 30056

You are kinda mixing the sort and filtering out phases. My solution

  1. Filter results with value >= 60
  2. Sort for values (descending, -v)
  3. Extract the first element for every array (the language name)

    def my_languages(results)
      results.select { |k, v| v >= 60 }.sort_by { |(k,v)| -v }.map(&:first)
    end
    

Upvotes: 4

Related Questions