Reputation: 4897
I have the following hash
{"f"=>[0, 1], "i"=>[1, 2], "n"=>[2, 2], "d"=>[3, 1], "g"=>[6, 1]}
I ultimately want to grab this value out of it "i"=>[1, 2]
. I want to grab this value because the logic is that out of all these characters in some string, i
has the highest value of occurrences 2
but appears first in a string given by its index in the array 1.
So for a string 'finding'
the i
character would be the first returned. I've made it so I generated this hash, now I just need to sort it so that the character that has the lowest index but the highest count will be first. Does anyone have an elegant solution to this?
Upvotes: 1
Views: 57
Reputation: 58244
In the Ruby sort_by
block, Ruby can compare arrays, which is done in element order. In your case, you want reverse order by the second element of the array, then order by first element. So you can construct your sort block as follows:
arr = {"f"=>[0, 1], "i"=>[1, 2], "n"=>[2, 2], "d"=>[3, 1], "g"=>[6, 1]}
arr.sort_by { |a| [-a[1][1], a[1][0]] }.first
Ruby firsts converts arr
to an array that looks like this:
[["f", [0, 1]], ["i", [1, 2]], ["n", [2, 2]], ["d", [3, 1]], ["g", [6, 1]]]
Then for each element that looks like [letter, [position, count]]
(represented by the sort block argument, a
), it is comparing [-count, position]
for the sort.
This will give:
["i", [1,2]]
You can then do with that form whatever you wish.
Note, you can use max_by ...
instead of sort_by ... .first
in the above. I completely forgot about max_by
, but Jörg W Mittag's nice answer reminded me.
Upvotes: 1
Reputation: 369458
If I understand the question correctly, there is no need to sort the hash at all to get the answer you are looking for, since you never actually need the sorted hash, you only need the maximum.
So, something like this should do the trick:
hash.max_by {|(_, (idx, frequency))| [frequency, -idx] }
#=> [?i, [1, 2]]
The entire thing would then look something like this:
str = 'Hello Nett'
str.
each_char.
with_index.
each_with_object(Hash.new {|h, k| h[k] = [0, nil]}) do |(char, idx), acc|
next unless /\p{Alphabetic}/ === char
char = char.downcase
acc[char][1] ||= idx
acc[char][0] += 1
end.
max_by {|(_, (frequency, idx))| [frequency, -idx] }
#=> [?n, [2, 1]]
Upvotes: 1