Reverse a hash in Ruby
You could convert the Hash to an Array, reverse that, and then convert it back to a Hash:
reversed_h = Hash[h.to_a.reverse]
Hash#to_a
gives you an array of arrays, the inner arrays are simple [key,value]
pairs, then you reverse that array using Array#reverse
, and Hash[]
converts the [key,value]
pairs back into a Hash.
Ruby 2.1 adds an Array#to_h
method so you can now say:
reversed_h = h.to_a.reverse.to_h
How to swap keys and values in a hash
Ruby has a helper method for Hash that lets you treat a Hash as if it was inverted (in essence, by letting you access keys through values):
{a: 1, b: 2, c: 3}.key(1)
=> :a
If you want to keep the inverted hash, then Hash#invert should work for most situations:
{a: 1, b: 2, c: 3}.invert
=> {1=>:a, 2=>:b, 3=>:c}
BUT...
If you have duplicate values, invert
will discard all but the last occurrence of your values (because it will keep replacing new value for that key during iteration). Likewise, key
will only return the first match:
{a: 1, b: 2, c: 2}.key(2)
=> :b
{a: 1, b: 2, c: 2}.invert
=> {1=>:a, 2=>:c}
So, if your values are unique you can use Hash#invert
. If not, then you can keep all the values as an array, like this:
class Hash
# like invert but not lossy
# {"one"=>1,"two"=>2, "1"=>1, "2"=>2}.inverse => {1=>["one", "1"], 2=>["two", "2"]}
def safe_invert
each_with_object({}) do |(key,value),out|
out[value] ||= []
out[value] << key
end
end
end
Note: This code with tests is now on GitHub.
Or:
class Hash
def safe_invert
self.each_with_object({}){|(k,v),o|(o[v]||=[])<<k}
end
end
What are some nice ways to reverse a nested hash?
This can be accomplished with a recursive method for inverting the keys of the hash (and values, if desired). For example:
hsh = {{"c"=>"b"}=>"a"}
def recursive_invert(hsh)
hsh.each_with_object({}) do |(k, v), inverted_hsh|
if k.is_a? Hash
k = recursive_invert(k)
end
inverted_hsh[v] = k
end
end
recursive_invert(hsh) # {"a"=>{"b"=>"c"}}
Sorting a complex ruby hash works fine, but it's impossible to reverse, what can I do?
reverse
reverses the current order. That means you have to sort first and reverse in a second step:
something.sort.reverse.each { ... }
Or you need to explicitly tell Ruby how to sort:
something.sort_by { |commit_id, _| -commit_id }.each { ... }
How to reverse hash to string conversion?
Looks like you need conversion from JSON to hash. (See DOCS). But, when you do to_s
the output is not in pure JSON format. So, you may see I'm using gsub
to replace =>
with :
require 'json'
hash = {"description" => "test"}
=> {"description"=>"test"}
str = hash.to_s.gsub("=>", ":")
=> "{\"description\":\"test\"}"
JSON.parse(str)
=> {"description"=>"test"}
reversing hash.sort_by in ruby
@sortedInternalLinksHash = @countHash.sort_by { |k,v| v }.reverse
Reversing a hash and merging keys in ruby
res = {}
h.each{|k, v| v.each{|vv| res[vv] ||= []; res[vv].push(k)}}
Hash invert in Ruby?
hash = {:key1 => ["a", "b", "c"], :key2 => ["d", "e", "f"]}
first variant
hash.map{|k, v| v.map{|f| {f => k}}}.flatten
#=> [{"a"=>:key1}, {"b"=>:key1}, {"c"=>:key1}, {"d"=>:key2}, {"e"=>:key2}, {"f"=>:key2}]
or
hash.inject({}){|h, (k,v)| v.map{|f| h[f] = k}; h}
#=> {"a"=>:key1, "b"=>:key1, "c"=>:key1, "d"=>:key2, "e"=>:key2, "f"=>:key2}
UPD
ok, your hash is:
hash = {"status"=>{"1"=>["1", "14"], "2"=>["7", "12", "8", "13"]}}
hash["status"].inject({}){|h, (k,v)| v.map{|f| h[f] = k}; h}
#=> {"12"=>"2", "7"=>"2", "13"=>"2", "8"=>"2", "14"=>"1", "1"=>"1"}
Ruby - How to invert a Hash with an array values?
h = {"Book Y"=>["author B", "author C"], "Book X"=>["author A", "author B", "author C"]}
p h.inject(Hash.new([])) { |memo,(key,values)|
values.each { |value| memo[value] += [key] }
memo
}
# => {"author B"=>["Book Y", "Book X"], "author C"=>["Book Y", "Book X"], "author A"=>["Book X"]}
Sort_by in Hash - reverse or not reverse - how?
Reverse does work:
library = {"1"=>{"title"=>"bbb", "money"=>10}, "2"=>{"title"=>"aaa", "money"=>12}}
sort_column = "money"
sort_direction = "asc"
library
.sort_by {|k| k[1][sort_column]}
.tap { |l| l.reverse! if sort_direction == "desc" }
# => [["1", {"title"=>"bbb", "money"=>10}], ["2", {"title"=>"aaa", "money"=>12}]]
sort_direction = "desc"
library
.sort_by {|k| k[1][sort_column]}
.tap { |l| l.reverse! if sort_direction == "desc" }
# => [["2", {"title"=>"aaa", "money"=>12}], ["1", {"title"=>"bbb", "money"=>10}]]
Related Topics
How to Select Array Elements in a Given Range in Ruby
Passing Binding or Arguments to Erb from the Command Line
C1 or C2 Coverage Tool for Ruby
Making a Soap Request by Using Xml in Rails
Using Will_Paginate Without :Total_Entries to Improve a Lengthy Query
Actiondispatch::Http::Uploadedfile.Content_Type Not Being Initialized in Rspec Test
Is the Unix Philosophy Falling Out of Favor in the Ruby Community
How to Print Something Without a New Line in Ruby
What Grammar Based Parser-Generator Tools Exist for Ruby
How to Detect Browser Type and Its Version
Carrierwave Fog Amazon S3 Images Not Displaying
Is There a Ruby Http Client Library with a Response Cache
How to Return Correct Http Error Codes from Ruby on Rails Application
Omniauth Facebook Expired Token Error
Convert Hash to Openstruct Recursively