Khachatur Saribekyan
Khachatur Saribekyan

Reputation: 97

Hash sorting alphabetiacly in ruby

I have the following hash.

h = {
    "31d2fcd5-aec0-438d-895c-806fd0358c23"=>{"name"=>"q", 'database'=>'mysql'},
    "69a05dea-d767-44b7-b40c-f76d0d12f8c1"=>{"name"=>"Qwerty", 'database'=>'H2'},
    "69a05dea-d767-44b7-b40c-f76d0d121993"=>{"name"=>"b", 'database'=>'postgresql'},
    "69a05dea-d767-44b7-b40c-f76d0d121994"=>{"name"=>"B", 'database'=>'oracle'},
    "69a05dea-d767-44b7-b40c-f76d0d121995"=>{"name"=>"Apple", 'database'=>'sqlite3'},
    "69a05dea-d767-44b7-b40c-f76d0d521996"=>{"name"=>"a", 'database'=>'mariadb'},
    "69a05dea-d767-44b7-b40c-f76d0d1k1996"=>{"name"=>"A", 'database'=>'mongodb'}
}

After sorting I would like to see it in the following form

h = {
     "31d2fcd5-aec0-438d-895c-806fd0358c23"=>{"name"=>"a", 'database'=>'mariadb'},
     "69a05dea-d767-44b7-b40c-f76d0d12f8c1"=>{"name"=>"A", 'database'=>'mongodb'},
     "69a05dea-d767-44b7-b40c-f76d0d121993"=>{"name"=>"Apple", 'database'=>'sqlite3'},
     "69a05dea-d767-44b7-b40c-f76d0d121994"=>{"name"=>"b", 'database'=>'postgresql'},
     "69a05dea-d767-44b7-b40c-f76d0d121995"=>{"name"=>"B", 'database'=>'oracle'},
     "69a05dea-d767-44b7-b40c-f76d0d521996"=>{"name"=>"q", 'database'=>'mysql'},
     "69a05dea-d767-44b7-b40c-f76d0d1k1996"=>{"name"=>"Qwerty", 'database'=>'H2'}
}

Thanks in advance.

Upvotes: 0

Views: 57

Answers (3)

Cary Swoveland
Cary Swoveland

Reputation: 110755

For Ruby v.1.9.3+,

h.sort_by { |_,v| [v["name"][0].downcase, v["name"]] }.to_h
  #=> {"69a05dea-d767-44b7-b40c-f76d0d1k1996"=>{"name"=>"A", "database"=>"mongodb"},
  #    "69a05dea-d767-44b7-b40c-f76d0d121995"=>{"name"=>"Apple", "database"=>"sqlite3"},
  #    "69a05dea-d767-44b7-b40c-f76d0d521996"=>{"name"=>"a", "database"=>"mariadb"},
  #    "69a05dea-d767-44b7-b40c-f76d0d121994"=>{"name"=>"B", "database"=>"oracle"},
  #    "69a05dea-d767-44b7-b40c-f76d0d121993"=>{"name"=>"b", "database"=>"postgresql"},
  #    "69a05dea-d767-44b7-b40c-f76d0d12f8c1"=>{"name"=>"Qwerty", "database"=>"H2"},
  #    "31d2fcd5-aec0-438d-895c-806fd0358c23"=>{"name"=>"q", "database"=>"mysql"}}

See the third paragraph of the doc for Array#<=> for an explanation of how Ruby orders arrays, which determines their sorted order.

My result differs from yours in the secondary sort. Your primary sort is

["q", "Qwerty", "b", "B", "Apple", "a", "A"].sort_by { |s| s[0].downcase }
  #=> ["a", "Apple", "A", "B", "b", "q", "Qwerty"] 

which is fine, but your secondary sort on strings beginning with "a" or "A", which you want to be

["a", "A", "Apple"]

is neither

["a", "Apple", "A"].sort
  # => ["A", "Apple", "a"]

nor

["a", "Apple", "A"].sort.reverse
  #=> ["a", "Apple", "A"]

so this begs the question, "what is your secondary sort criterion"?

Upvotes: 0

spickermann
spickermann

Reputation: 107142

Short answer: You can't. See the docs about hashes in Ruby 1.8.7:

The order in which you traverse a hash by either key or value may seem arbitrary, and will generally not be in the insertion order.

In Ruby 1.8.7 hashes are not ordered. It is not even guaranteed that the order matches the order in which the keys were inserted (like it would be in Ruby 1.9+).

That said: You will have to use a different data structure, like an array for example. Arrays can be sorted by its first value and they would keep that order.

Btw: Ruby 1.8.7 is outdated more many years already (its successor Ruby 1.9 was released six years ago). Ruby 1.8.7 is missing some interesting features, doesn't get security updates anymore and many gems dropped support for this old version. I advise to update to at least Ruby 2.2+

Upvotes: 4

Mikhail Chuprynski
Mikhail Chuprynski

Reputation: 2493

As it is written in RubyDocs:

Hashes enumerate their values in the order that the corresponding keys were inserted.

So you need to create new hash for your purposes:

h.to_a.sort_by{|s| s[1]['name']}.to_h

{
  "69a05dea-d767-44b7-b40c-f76d0d1k1996"=>{"name"=>"A", "database"=>"mongodb"}, 
  "69a05dea-d767-44b7-b40c-f76d0d121995"=>{"name"=>"Apple", "database"=>"sqlite3"}, 
  "69a05dea-d767-44b7-b40c-f76d0d121994"=>{"name"=>"B", "database"=>"oracle"}, 
  "69a05dea-d767-44b7-b40c-f76d0d12f8c1"=>{"name"=>"Qwerty", "database"=>"H2"}, 
  "69a05dea-d767-44b7-b40c-f76d0d521996"=>{"name"=>"a", "database"=>"mariadb"}, 
 "69a05dea-d767-44b7-b40c-f76d0d121993"=>{"name"=>"b", "database"=>"postgresql"}, 
 "31d2fcd5-aec0-438d-895c-806fd0358c23"=>{"name"=>"q", "database"=>"mysql"}
}

Upvotes: 0

Related Questions