Sort a hash whose values are all 5-element arrays on the i-th element of the array

I have a hash with keys == text phrases, and values == five element arrays, eg

     thishash = ( asi: [1,2,3,4,5], kvr: [60,11,24 1,0], bitt: [0,0,3,-2,5]}

I’d like to sort it in descending order on the ith (right now it’s fifth) element of the array, and then in ascending alphabetical order of the key, if necessary. How do I do that?

You can’t sort a hash, as such. It’s intended to be a random-access data-structure.

You could extract key-value pairs into an array, and then sort. What do you want to do with the sorted structure?

When you sort a Hash with .sort() method, it converts your hash to an array and sorts the hash based on the keys. If you want to sort hash by keys and get hash, you have to use hash.sort.to_h. It’s very slow, but will get your job done. Here’s an example of sorting the arrays in ascending order and the hash keys in descending order:

thishash = {asi: [1,2,3,4,5], kvr: [60,11,24, 1,0], bitt: [0,0,3,-2,5]}.reduce({}) { |x, y| x.merge!( {y[0] => y[1].sort} ) }.sort { |x, y| y <=> x }.to_h

As you can see it involves multiple loops. But the output is:

{:kvr=>[0, 1, 11, 24, 60], :bitt=>[-2, 0, 0, 3, 5], :asi=>[1, 2, 3, 4, 5]}

I hope you want such thing, I apologize, I don’t get your question clearly.

right now it’s fifth

If you want to sort the last array, you have to get the last element: thishash[:bitt].sort! to sort it. To sort the absolute last array value of any hash: thishash.values[-1].sort!.

Thank you, but this isn’t what I need. I need to sort the hash on the value of the 5th element of each of the arrays–I don’t want the arrays sorted: I want the key,value pair whose array contains the largest 5th element to become the first element of the hash, and so on–I know I’ll need some reversal for the descending order; keys should sort in ascending order.

Yes. Since I seem to have failed to find this particular sort (sort_by will handle hashes with single values, creating arrays that .to_h will put back into a hash) I intend to extract the key and relevant value, sort on those and read my hash in that order.

Uh, maybe you want this:

p {asi: [1,2,3,4,5], kvr: [60,11,24, 1,0], bitt: [0,0,3,-2,5]}.sort_by { |x| x[1][4] }

Outputs:

[[:kvr, [60, 11, 24, 1, 0]], [:asi, [1, 2, 3, 4, 5]], [:bitt, [0, 0, 3, -2, 5]]]

If you have more items:

thishash = {a: [1, 2, 3, 4, 5], b: [60, 11, 24, 1, 0], c: [0,0,3,-2,5], d: [1, 1, 1, 1, 100], e: [1, 1, 1, 1, -100] }.sor
t_by { |x| x[1][4] }.to_h

Sets this hash to:

{:e=>[1, 1, 1, 1, -100], :b=>[60, 11, 24, 1, 0], :a=>[1, 2, 3, 4, 5], :c=>[0, 0, 3, -2, 5], :d=>[1, 1, 1, 1, 100]}

So it sorts the items based on the 5th element. But if you don’t have the 5th element, maybe you will need to convert the nil into 0 using .to_i or something similar…

Thank you! That’s exactly what I want, and I had been trying things of this nature–I thought that I had tried that one, but obviously I hadn’t.
The nature of my project insures that if an array has a different number of elements, there is something wrong with the input.