Ruby: Converting a nested Ruby hash to an un-nested one
Here's a first cut at a complete solution. I'm sure you can write it more elegantly, but this seems fairly clear. If you save this in a Ruby file and run it, you'll get the output I show below.
class Hash
def unnest
new_hash = {}
each do |key,val|
if val.is_a?(Hash)
new_hash.merge!(val.prefix_keys("#{key}-"))
else
new_hash[key] = val
end
end
new_hash
end
def prefix_keys(prefix)
Hash[map{|key,val| [prefix + key, val]}].unnest
end
end
p ({"a" => 2, "f" => 5}).unnest
p ({"a" => {"b" => 3}, "f" => 5}).unnest
p ({"a" => {"b" => {"c" => 4}, "f" => 5}}).unnest
Output:{"a"=>2, "f"=>5}
{"a-b"=>3, "f"=>5}
{"a-b-c"=>4, "a-f"=>5}
Merge nested hash without overwritting in Ruby
For Rails there is the deep_merge
function for ActiveSupport
that does exactly what you ask for.
You can implement the same for yourself as follows:
class ::Hash
def deep_merge(second)
merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 }
self.merge(second, &merger)
end
end
Now,h1 = {"a"=>"text"}
h2 = {"b"=>{"x"=>"hola"}}
h3 = {"b"=>{"y"=>"pto"}}
h1.deep_merge(h2).deep_merge(h3)
# => {"a"=>"text", "b"=>{"x"=>"hola", "y"=>"pto"}}
How do I flatten a nested hash, recursively, into an array of arrays with a specific format?
As hinted at in the comments:
Looks pretty straightforward. Descend into hashes recursively, taking note of keys you visited in this branch. When you see an array, no need to recurse further. Append it to the list of keys and returnI meant something like this:Tracking is easy, just pass the temp state down to recursive calls in arguments.
def tree_flatten(tree, path = [], &block)
case tree
when Array
block.call(path + tree)
else
tree.each do |key, sub_tree|
tree_flatten(sub_tree, path + [key], &block)
end
end
end
tree_flatten(tree_def) do |path|
p path
end
This code simply prints each flattened path as it gets one, but you can store it in an array too. Or even modify tree_flatten
to return you a ready array, instead of yielding elements one by one. How to iterate over a nested Ruby hash to add a new key/value pair based on existing key/value data?
In addition to @MurifoX answer, you can use #transform_values
ages.transform_values do |value|
if value["age"] >= 65
value["age_group"] = "senior"
elsif value["age"] > 17 && value["age"] < 65
value["age_group"] = "adult"
else
value["age_group"] = "kid"
end
end
How to set nested hash in ruby dynamically?
Hash#[]=
is a single method. You cannot do Hash#[]
all the way to the last key and do =
to it. Rather, leave out the last key and do Hash#[]=
individually on it.
*key, last = key.split(".")
key.inject(h, :fetch)[last] = "b"
rails nested hash with default values
The doc for Hash::new explains the three ways of initializing a hash and, in your case, you are using an object in the Hash constructor:
If you want that each missing key creates it's own object, create the hash with a block, like this:If obj is specified, this single object will be used for all default values.
h = Hash.new { |h,k| h[k] = { count: 0, rating: 0 } }
Then:2.6.3 :012 > h
=> {}
2.6.3 :013 > h['a'][:count] = 5
=> 5
2.6.3 :015 > h
=> {"a"=>{:count=>5, :rating=>0}}
(Ruby) How to convert a nested hash into a csv file
I would do something like this:
require 'csv'
CSV.open('the_file.csv', 'w') do |csv|
hash.each do |id, attributes|
csv << [id, *attributes.values_at(:price, :brand)]
end
end
How to avoid NoMethodError for missing elements in nested hashes, without repeated nil checks?
Ruby 2.3.0 introduced a method called dig
on both Hash
and Array
.
name = params.dig(:company, :owner, :name)
It returns nil
if the key is missing at any level.If you are using a version of Ruby older than 2.3, you can install a gem such as ruby_dig
or hash_dig_and_collect
, or implement the functionality yourself:
module RubyDig
def dig(key, *rest)
if value = (self[key] rescue nil)
if rest.empty?
value
elsif value.respond_to?(:dig)
value.dig(*rest)
end
end
end
end
if RUBY_VERSION < '2.3'
Array.send(:include, RubyDig)
Hash.send(:include, RubyDig)
end
Related Topics
Ruby Datamapper Table Inheritance with Associations
Combining Ruby on Rails and Backbone
Error While Starting Puma Server with Workers
How to Stub/Mock a Call to The Command Line with Rspec
How to Flush HTML to The Wire in Sinatra
Explanation of Ruby Code for Building Trie Data Structures
Heroku Repo Size and Slug Size Increase with Each Deployment. Why
Heroku Process Exits with Status 0 But Its Dyno Still "Crashes"
How to Install Wraith on Windows 7
Using Update_Columns in Rails 3
List Array of Days Between Two Dates
How Do Erlang Actors Differ from Oop Objects
Accessing Microsoft Exchange Server from Ruby
Using Rails with Paperclip and Swfupload
Rack: How to Store The Url as a Variable
How to Fix Difference in Behavior of Activesupport 3.0.0 Compare to 2.X
How to Compare Xml Output in a Cucumber Step Using a Multiline String Example