replace all the values of a hash sequentially with respect to an array - ruby

Suppose I have a hash,
hash = { "name" = > nil, "product" => nil , "price" => nil }
and an array
a = [ "Bob" , "Fryer" , "20$"]
I would like the output be hash
{ "name" => "Bob" , "product" => "Fryer" , "price" => "20$"}
Tried with zip, merge and map, couldn't get the right one

Try
Hash[hash.keys.zip(a)]
=> {"name"=>"Bob", "product"=>"Fryer", "price"=>"20$"}

You can get keys and zip it with array:
hash.keys.zip(a).to_h
=> {"name"=>"Bob", "product"=>"Fryer", "price"=>"20$"}

Related

how can i perform a query on a hash, and get result another hash?

I am trying to do a query against a ruby hash, which is much alike this:
{"client1" => {"tag" => "13", "host" => "client1.example.com", ...}, "client2" => {"tag" => "11", ...} }
and I would like to map it to only the client names with their tags, like this:
{"client1" => "13", "client2" => "11"}
I have been struggeling with .each and .select and .find but haven't figured it out yet. I am pretty sure it is not that hard, does anybody know? Thanks
You could do the same as below
data = {
"client1" => {"tag" => "13", "host" => "client1.example.com"},
"client2" => {"tag" => "11"}
}
desired_data = Hash.new
data.each do |k,v|
desired_data[k] = v["tag"]
end
desired_data will contain your result.
As suggested by #sawa you could also use
data.each_with_object({}){|(k, v), h| h[k] = v["tag"]}
Use map:
test_hash = {"client1" => {"tag" => "13", "host" => "client1.example.com"}, "client2" => {"tag" => "11"} }
test_hash.map{|k,v| [k, v['tag']]}.to_h
#=> {"client1"=>"13", "client2"=>"11"}
One way is to merge the hash with itself, using the form of Hash#merge that employs a block to determine the values of keys that are present in both hashes being merged, which in this case is all keys.
h = {"client1" => {"tag" => "13", "host" => "client1.example.com"},
"client2" => {"tag" => "11"} }
h.merge(h) { |*,v| v["tag"] }
#=> {"client1"=>"13", "client2"=>"11"}
As explained in the doc, the block has three variables, often written |key, old_value, new_value|. Here old_value and new_value are the same. The asterisk in |*, new_value| is a placeholder for all but the last block variable.

How to generate direct access keys to nested hash which contains hash and arrays as values?

I want to compare two XML files where one is input and the other is output. I am converting both into a hash.
My idea is to get all the keys from the input XML converted to hash, and search each key in both the input and output hashes for their respective key/value pairs.
I have a hash:
{
"requisition_header" => {
"requested_by" => {"login" => "coupasupport"},
"department" => {"name" => "Marketing"},
"ship_to_address" => {"name" => "Address_1431693296"},
"justification" => nil,
"attachments" => [],
"requisition_lines" => [
{
"description" => "Cleaning Services for Building A",
"line_num" => 1,
"need_by_date" => 2010-09-23 07:00:00 UTC,
"source_part_num" => nil,
"supp_aux_part_num" => nil,
"unit_price" => #<BigDecimal:a60520c,'0.3E4',9(18)>,
"supplier" => {"name" => "amazon.com"},
"account" => {
"code" => "SF-Marketing-Indirect",
"account_type" => {"name" => "Ace Corporate"}
},
"currency" => {"code" => "USD"},
"payment_term" => {"code" => "Net 30"},
"shipping_term" => {"code" => "Standard"},
"commodity" => {"name" => "Marketing-Services"}
}
]
}
}
It is nested and all the values are not directly accessible.
I want a way to generate direct access to each value in the hash.
For example:
requisition_header.requested_by.login
will access "coupasupport".
requisition_header.department.name
will access "Marketing".
requisition_header.requisition_lines[0].description
will access "Cleaning Services for Building A".
requisition_header.requisition_lines[0].line_num
will access "1".
requisition_header.requisition_lines[0].need_by_date
will access "2010-09-23 07:00:00 UTC".
Each key built can be used to search for the value directly inside the hash.
That could be done with the following method, that translates the nested hash into nested OpenStructs:
require 'ostruct'
def deep_structify(hash)
result = {}
hash.each do |key, value|
result[key] = value.is_a?(Hash) ? deep_structify(value) : value
end if hash
OpenStruct.new(result)
end
hash = {"requisition_header"=>{"requested_by"=>{"login"=>"coupasupport"}, "department"=>{"name"=>"Marketing"}, "ship_to_address"=>{"name"=>"Address_1431693296"}, "justification"=>nil, "attachments"=>[], "requisition_lines"=>[{"description"=>"Cleaning Services for Building A", "line_num"=>1, "need_by_date"=>2010-09-23 07:00:00 UTC, "source_part_num"=>nil, "supp_aux_part_num"=>nil, "unit_price"=>#<BigDecimal:a60520c,'0.3E4',9(18)>, "supplier"=>{"name"=>"amazon.com"}, "account"=>{"code"=>"SF-Marketing-Indirect", "account_type"=>{"name"=>"Ace Corporate"}}, "currency"=>{"code"=>"USD"}, "payment_term"=>{"code"=>"Net 30"}, "shipping_term"=>{"code"=>"Standard"}, "commodity"=>{"name"=>"Marketing-Services"}}]}}
struct = deep_structify(hash)
struct.requisition_header.department.name
#=> "Marketing"
You can do it by overriding OpenStruct#new as well,
require 'ostruct'
class DeepStruct < OpenStruct
def initialize(hash=nil)
#table = {}
#hash_table = {}
if hash
hash.each do |k,v|
#table[k.to_sym] = (v.is_a?(Hash) ? self.class.new(v) : v)
#hash_table[k.to_sym] = v
new_ostruct_member(k)
end
end
end
def to_h
#hash_table
end
end
Now you can do:
require 'deep_struct'
hash = {"requisition_header"=>{"requested_by"=>{"login"=>"coupasupport"}, "department"=>{"name"=>"Marketing"}, "ship_to_address"=>{"name"=>"Address_1431693296"}, "justification"=>nil, "attachments"=>[], "requisition_lines"=>[{"description"=>"Cleaning Services for Building A", "line_num"=>1, "need_by_date"=>2010-09-23 07:00:00 UTC, "source_part_num"=>nil, "supp_aux_part_num"=>nil, "unit_price"=>#<BigDecimal:a60520c,'0.3E4',9(18)>, "supplier"=>{"name"=>"amazon.com"}, "account"=>{"code"=>"SF-Marketing-Indirect", "account_type"=>{"name"=>"Ace Corporate"}}, "currency"=>{"code"=>"USD"}, "payment_term"=>{"code"=>"Net 30"}, "shipping_term"=>{"code"=>"Standard"}, "commodity"=>{"name"=>"Marketing-Services"}}]}}
mystruct = DeepStruct.new hash
mystruct.requisition_header.requested_by.login # => coupasupport
mystruct.requisition_header.to_h # => {"requested_by"=>{"login"=>"coupasupport"}
You could use BasicObject#method_missing:
Code
class Hash
def method_missing(key,*args)
(args.empty? && key?(key)) ? self[key] : super
end
end
Example
hash = { animals: {
pets: { dog: "Diva", cat: "Boots", python: "Stretch" },
farm: { pig: "Porky", chicken: "Little", sheep: "Baa" }
},
finishes: {
tinted: { stain: "Millers", paint: "Oxford" },
clear: { lacquer: "Target", varnish: "Topcoat" }
}
}
hash.finishes.tinted.stain
#=> "Millers
hash.animals.pets.cat
#=> "Boots"
hash.animals.pets
#=> {:dog=>"Diva", :cat=>"Boots", :python=>"Stretch"}
hash.animals
#=> {:pets=>{:dog=>"Diva", :cat=>"Boots", :python=>"Stretch"},
# :farm=>{:pig=>"Porky", :chicken=>"Little", :sheep=>"Baa"}}
Reader challenge
There is a potential "gotcha" with this approach. I leave it to the reader to identify it. My example contains a clue. (Mind you, there may be other problems I haven't thought of.)

Selecting single hash from array where one hash element has the highest value

From the following array of hashes, how can I select a single hash where timestamp has the highest value?
data = [
{"id" => 1, "timestamp" => 1383314276, "data" => "bea7c82f-f4b2-492a-aba3-033b1a54d9d0"},
{"id" => 2, "timestamp" => 1383314386, "data" => "64ed2ed9-763d-443f-a74e-e7f10cbe783e"},
{"id" => 3, "timestamp" => 1383314331, "data" => "f8cfaa99-ffe0-4d88-8fac-37e4ce462d3a"}
]
Here you can see:
data.max_by{|e| e["timestamp"] }
# >> {"id"=>2, "timestamp"=>1383314386, "data"=>"64ed2ed9-763d-443f-a74e-e7f10cbe783e"}

Including empty k/v pairs when merging hashes

There are three hashes. Each hash results in a single key/value pair.
When merged and outputted to a json file, the only k/v pairs visible are the ones with data.
For example:
employee_hours[ name ] = {"Hours" => hours}
employee_revenue [ name ] = {"Revenue" => revenue}
employee_activations [ name ] = {"Activations" => activations}
If any of the k/v pairs don't exist I need them to be included in the output with a value of 0.00.
I tried to simply just include empty k/v pairs from the other hashes in each hashtable, but when merged, they overwrite existed values.
employee_hours[ name ] = {"Hours" => hours, "Revenue" = "", Activations = ""}
employee_revenue [ name ] = {"Hours" => "", "Revenue" => revenue, Activations = ""}
employee_activations [ name ] = {"Hours" => "", "Revenue" => "", "Activations" => activations}
Edit
My current code is listed here: https://gist.github.com/hnanon/766a0d6b2b0f9d9d03fd
You need to define a hash for the default values and merge into it. Assuming that employee_final is the hash where you merged all the employee information,
employee_defaults = { "Hours" => 0.0, "Revenue" => 0.0 }
employee_final.each_key do |name|
employee_final[name] = employee_defaults.merge(employee_final[name])
end
It sounds as if you need to define a 'REQUIRED_KEYS' array, and add check on their existence in your hashes. Here's one way to achieve that:
REQUIRED_KEYS = [ "A", "B", "C" ]
DEFAULT_VALUE = 0.0
REQUIRED_KEYS.each { |key| your_hash[key] = DEFAULT_VALUE if not your_hash.has_key?(key) }
Use Hash Defaults
You can use an argument to Hash#new to set a default value for a hash. For example:
require 'json'
employee_hours = Hash.new(0.0)
employee_revenue = Hash.new(0.0)
employee_activations = Hash.new(0.0)
name = 'Bob'
{
'Hours' => employee_hours[name],
'Revenue' => employee_revenue[name],
'Activations' => employee_activations[name],
}.to_json
# => "{\"Hours\":0.0,\"Revenue\":0.0,\"Activations\":0.0}"

Shifting a specific matching key-value pair from Ruby hash

I have a Ruby hash:
#tags = { "project_status" => { "title" => "Project status" },
"milestones" => { "title" => "Milestones"},
"lessons" => { "title" => "Lessons"},
"tasks" => { "title" => "Tasks"} }
I'd like to shift specific key-value pairs out of this hash.
e.g. if I am interested in "milestones" tags, then shift on the hash will give me:
=> ["milestones", {"title"=>"Milestones"}]
Which is exactly what I want.
Except that I can't work out how to select a specific key-value pair.
I could write something to iterate through the hash until I find the matching key and then call shift, but I'm assuming there's a cleaner "Ruby way" to do this :)
delete is probably what you're looking for. It removes corresponding key from the hash (whereas shift removes item from an array)
tags = { "project_status" => { "title" => "Project status" },
"milestones" => { "title" => "Milestones"},
"lessons" => { "title" => "Lessons"},
"tasks" => { "title" => "Tasks"} }
def shift hash, key
[key, hash.delete(key)] # removes key/value pair
# [key, hash[key]] # leaves key/value pair
end
shift tags, 'milestones' # => ["milestones", {"title"=>"Milestones"}]
tags # => {"project_status"=>{"title"=>"Project status"}, "lessons"=>{"title"=>"Lessons"}, "tasks"=>{"title"=>"Tasks"}}

Resources