Replace hash value based on the value in another hash - ruby

Given two hashes, I'm trying to replace a value in the first hash for a key that the second hash also has. To be specific, I have these two hashes:
data = {
"study" => "Lucid Study",
"name" => "Lucid Plan",
"studyWillBe" => "Combination"
}
conditions = { "study" => "((current))" }
I want data to have its "study" key updated since conditions has that key. I want data to end up like this:
data = {
"study" => "((current))",
"name" => "Lucid Plan",
"studyWillBe" => "Combination"
}
I got this far:
data = Hash[data.map {|k, v| [conditions[k] || k, v] }]
but that's not quite doing the trick. Can anyone point me in the right direction?

You can do this
data.each {|k, v| data[k] = conditions[k] if conditions[k]}

It's called merge.
data = {"study"=>"Lucid Study", "name"=>"Lucid Plan", "studyWillBe"=>"Combination"}
conditions = {"study"=>"((current))"}
data.merge(conditions)
#{"study"=>"((current))", "name"=>"Lucid Plan", "studyWillBe"=>"Combination"}

The method merge can take a block where you can make some specific operation not only assign new value
data.merge(conditions) do |key, oldvalue, newvalue|
newvalue
end
=> {"study"=>"((current))", "name"=>"Lucid Plan", "studyWillBe"=>"Combination"}

Related

Manipulate hash in Ruby

I have a hash that looks like
{
"lt"=>"456",
"c"=>"123",
"system"=>{"pl"=>"valid-player-name", "plv"=>"player_version_1"},
"usage"=>{"trace"=>"1", "cq"=>"versionid", "stream"=>"od",
"uid"=>"9", "pst"=>[["0", "1", "10"]], "dur"=>"0", "vt"=>"2"}
}
How can I go about turning it into a hash that looks like
{
"lt"=>"456",
"c"=>"123",
"pl"=>"valid-player-name",
"plv"=>"player_version_1",
"trace"=>"1",
"cq"=>"versionid",
"stream"=>"od",
"uid"=>"9",
"pst"=>[["0", "1", "10"]], "dur"=>"0", "vt"=>"2"
}
I basically want to get rid of the keys system and usage and keep what's nested inside them
"Low-tech" version :)
h = { ... }
h.merge!(h.delete('system'))
h.merge!(h.delete('usage'))
Assuming no rails:
hash.reject { |key, _| %w(system usage).include? key }.merge(hash['system']).merge(hash['usage'])
With active support:
hash.except('system', 'usage').merge(hash['system']).merge(hash['usage'])
A more generic version.
Merge any key that contains a hash:
h = { ... }
hnew = h.inject(h.dup) { |h2, (k, v)|
h2.merge!(h2.delete(k)) if v.is_a?(Hash)
h2
}
Assuming that your data has the same structure each time, I might opt for something simple and easy to understand like this:
def manipulate_hash(h)
{
"lt" => h["lt"],
"c" => h["c"],
"pl" => h["system"]["pl"],
"plv" => h["system"]["plv"],
"trace" => h["usage"]["trace"],
"cq" => h["usage"]["cq"],
"stream" => h["usage"]["stream"],
"uid" => h["uid"],
"pst" => h["pst"],
"dur" => h["dur"],
"vt" => h["vt"]
}
end
I chose to make the hash using one big hash literal expression that spans multiple lines. If you don't like that, you could build it up on multiple lines like this:
def manipulate_hash
r = {}
r["lt"] = h["lt"]
r["c"] = h["c"]
...
r
end
You might consider using fetch instead of the [] angle brackets. That way, you'll get an exception if the expected key is missing from the hash. For example, replace h["lt"] with h.fetch("lt").
If you plan to have an arbitrarily large list of keys to merge, this is an easily scaleable method:
["system", "usage"].each_with_object(myhash) do |key|
myhash.merge!(myhash.delete(key))
end

How to print only a value in key value pair

This is my code
lunch_order = {
"Ryan" => "wonton soup",
"Eric" => "hamburger",
"Jimmy" => "sandwich",
"Sasha" => "salad",
"Cole" => "taco"
}
lunch_order.each { |element| puts element }
I want the value to be printed out, but here, both the value and the key are printed.
You can use
lunch_order.each { |key, value| puts value}
Codepad Example
You can loop over the values only with each_value
h = { "a" => 100, "b" => 200 }
h.each_value {|value| puts value }
You can read more about api of hash here.
So many ways to do it in Ruby:
lunch_order.values.each { |element| puts element }
In Ruby a hash contains Keys and Values. So in your case the keys are:
Keys
Ryan
Eric
Jimmy
Sasha
Cole
And the Values for those keys are:
Values
Wonton Soup
Hamburger
Sandwich
Salad
Taco
And all you'd need to do to call the values is use the each loops like you've done but instead of using element as the local variable within the block, you use something like this:
lunch_order.each do { |key, value| puts value }
lunch_order.each_pair { |key,value| puts value }
Docs: http://apidock.com/ruby/Hash/each_pair
Given your original code
lunch_order = {
"Ryan" => "wonton soup",
"Eric" => "hamburger",
"Jimmy" => "sandwich",
"Sasha" => "salad",
"Cole" => "taco"
}
You created a hash, which consists of both keys and values. Keys are on the left, values on the right. To get only the values use
lunch_order.values.each{|value| puts value}
Hope this helps.

dynamically finding value from key string in nested hash

I have a user inputed string called x_value whose value contains something like ticker|high. Whenever there is a |, that indicates that the latter is a child of the former. The purpose of the method is to return a specific value within a hash.
sections = []
object.x_value.split('|').each do |part|
sections << part.to_sym
end
I then want to drill down the data hash and retrieve the value of the last key.
data = {"ticker":{"high":529.5,"low":465,"avg":497.25,"vol":7520812.018}}
In this example
data[sections[0]][sections[1]] returns the expected 529.5 value. However, the user may have different hashes and different levels deep of nested key/values. How can I write this?
I have tried data[sections], but that didn't work.
Use Enumerable#reduce
data = {"ticker" => {"high" => 529.5, "low" => 465,"avg" => 497.25,"vol" => 7520812.018}}
"ticker|high".split('|').reduce(data) { |dat,val| dat[val] } #=> 592.5
more example:
data = {"more_ticker" => {"ticker" => {"high" => 529.5, "low" => 465,"avg" => 497.25,"vol" => 7520812.018}}}
"more_ticker|ticker|avg".split('|').reduce(data) { |dat,val| dat[val] }
#=> 497.25
You could also use recursion:
def getit(hash, x_value)
recurse(hash, x_value.split('|'))
end
def recurse(hash, keys)
k = keys.shift
keys.empty? ? hash[k] : recurse(hash[k], keys)
end
data = {"ticker" => {"high" => 529.5, "low" => 465}}
getit(data, "ticker|high") #=> 529.5
getit(data, "ticker") #=> {"high"=>529.5, "low"=>465}
data = {"more_ticker" => {"ticker" => {"high" => 529.5, "low" => 465}}}
getit(data, "more_ticker|ticker|low") #=> 465
getit(data, "more_ticker|ticker|avg") #=> nil

How to get the first key and value pair from a hash table in Ruby

I'm trying to get the first key and value key from a hash table in ruby. I don't know the key values of the hash because it is passed to the method. I cant find anywhere online how to find the first key/value as a separate hash table.
I think hash[0] will just try to find an element with a name 0 it just returns nil when I run the code.
I know I can find the key name and the value and then create a new hash from them but i wonder if there is an easier way to do this so I get a hash right away.
here is my code:
def rps_game_winner(game)
rock_in_hash = game.invert['R']
paper_in_hash = game.invert['P']
scissors_in_hash = game.invert['S']
if(rock_in_hash)
if(paper_in_hash)
return paper_in_hash;
elsif(scissors_in_hash)
return rock_in_hash
end
elsif(paper_in_hash)
if(rock_in_hash)
return paper_in_hash
elsif(scissors_in_hash)
return scissors_in_hash
end
end
key = game.keys[-1]
value = game.values[-1]
winner = {key => value}
return winner
end
game_one = { "Bob" => 'P', "Jim" => 'P' }
puts rps_game_winner(game_one)
This gets me the correct result the problem is I don't understand why it's -1 instead of zero...
And i was hoping there was a better way to get the first key/value pair of a hash table instead of creating new hash table with the key and value you retrieved from the previous table.
You can just do
key, value = hash.first
or if you prefer:
key = hash.keys[0]
value = hash.values[0]
Then maybe:
new_hash = {key => value}
There is a shorter answer that does not require you to use extra variables:
h = { "a" => 100, "b" => 200 , "c" => 300, "d" => 400, "e" => 500}
Hash[*h.first] #=> {"a" => 100}
Or if you want to retrieve a key/value at a any single position
Hash[*h.to_a.at(1)] #=> {"b" => 200}
Or retrieve a key/values from a range of positions:
Hash[h.to_a[1,3]] #=> {"b"=>200, "c"=>300, "d"=>400}
[hash.first].to_h
Another way to do it.
my_hash = { "a" => "first", "b" => "second" }
{ my_hash.keys.first => my_hash.values.first }
This works too

Ruby - Array of Hashes, Trying to Select Multiple Keys and Group By Key Value

I have a set of data that is an array of hashes, with each hash representing one record of data:
data = [
{
:id => "12345",
:bucket_1_rank => "2",
:bucket_1_count => "12",
:bucket_2_rank => "7",
:bucket_2_count => "25"
},
{
:id => "45678",
:bucket_1_rank => "2",
:bucket_1_count => "15",
:bucket_2_rank => "9",
:bucket_2_count => "68"
},
{
:id => "78901",
:bucket_1_rank => "5",
:bucket_1_count => "36"
}
]
The ranks values are always between 1 and 10.
What I am trying to do is select each of the possible values for the rank fields (the :bucket_1_rank and :bucket_2_rank fields) as keys in my final resultset, and the values for each key will be an array of all the values in its associated :bucket_count field. So, for the data above, the final resulting structure I have in mind is something like:
bucket 1:
{"2" => ["12", "15"], "5" => ["36"]}
bucket 2:
{"7" => ["25"], "9" => ["68"]}
I can do this working under the assumption that the field names stay the same, or through hard coding the field/key names, or just using group_by for the fields I need, but my problem is that I work with a different data set each month where the rank fields are named slightly differently depending on the project specs, and I want to identify the names for the count and rank fields dynamically as opposed to hard coding the field names.
I wrote two quick helpers get_ranks and get_buckets that use regex to return an array of fieldnames that are either ranks or count fields, since these fields will always have the literal string "_rank" or "_count" in their names:
ranks = get_ranks
counts = get_counts
results = Hash.new{|h,k| h[k] = []}
data.each do |i|
ranks.each do |r|
unless i[r].nil?
counts.each do |c|
results[i[r]] << i[c]
end
end
end
end
p results
This seems to be close, but feels awkward, and it seems to me there has to be a better way to iterate through this data set. Since I haven't worked on this project using Ruby I'd use this as an opportunity to improve my understanding iterating through arrays of hashes, populating a hash with arrays as values, etc. Any resources/suggestions would be much appreciated.
You could shorten it to:
result = Hash.new{|h,k| h[k] = Hash.new{|h2,k2| h2[k2] = []}}
data.each do |hsh|
hsh.each do |key, value|
result[$1][value] << hsh["#{$1}_count".to_sym] if key =~ /(.*)_rank$/
end
end
puts result
#=> {"bucket_1"=>{"2"=>["12", "15"], "5"=>["36"]}, "bucket_2"=>{"7"=>["25"], "9"=>["68"]}}
Though this is assuming that :bucket_2_item_count is actually supposed to be :bucket_2_count.

Resources