First appearance of specific key in subhashes - ruby

I have an array:
array = [{"number" => "7", "disk" => "70"},{"number" => "12", "disk" => "150", "global" => "yes"},{"number" => "8", "disk" => "250", "global" => "yes"}]
I want to define a string containing the value of the first "global" key appearance. I know how to loop over that hash, but I can't figure out how to define the first appearance of that key.

array.each { |h| break h["global"] if h["global"] }

Related

Merging two arrays of hashes in Ruby

I’m very close to solving a project I’ve been working on for a while but can’t seem to figure this out.
array1 = [{:new_listing => "1", :item => "apple"}, {:new_listing => "2", :item => "bannana"}]
array2 = [{:height => "10"}, {:height => "12"}]
How do I merge them so it is
[{:new_listing => "1", :item => "apple", :height => "10" },
{:new_listing => "2", :item => "bannana", :height => "12"}]
The order of each arrays are aligned, and should be the same size. Some values of array2 will be {:height => nil}.
The order of each arrays are aligned, and should be the same size.
That's exactly the description of the zip method.
zip(arg, ...) → an_array_of_array
Takes one element from enum and merges corresponding elements from each args.
Likewise, merging hashes is done with merge
array1.zip(array2).map { |x, y| x.merge(y) }
array1.map {|x| x.merge!(array2.shift) }
use map/each as per your requirement
Below solution should work for you:
array1 = [{:new_listing=> "1", :item=> "apple"}, {:new_listing=> "2", :item=> "bannana"}]
array2 = [{:height=> "10"},{:height => "12"}]
array2.each_with_index { |hash, index| array1[index] = array1[index].merge(hash) }
puts array1
# [{:new_listing=>"1", :item=>"apple", :height=>"10"}, {:new_listing=>"2", :item=>"bannana", :height=>"12"}]

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.

Count the occurence of values in Ruby

I'm trying to count numbers of different values in mysql table columns. Range of possible values is integer and from 0-10. The following code is working, but I'm wondering if there is a more elegant way to do this?
# Example data from Mysql
result = [{ :column1 => "2", :column2 => "3", :column3 => "1"},{ :column1 => "2", :column2 => "3", :column3 => "1"},{ :column1 => "1", :column2 => "2", :column3 => "3"}]
# Init hash
final_result = Hash.new { |h, k| h[k] = { } }
# Loop result columns
result.each do |single_column|
# Loop single items inside columns
single_column.each do |single_result|
# Create column if does not exist
if final_result[single_result[0]][single_result[1]].nil? then
final_result[single_result[0]][single_result[1]] = 1
else
final_result[single_result[0]][single_result[1]] += 1
end
end
end
puts final_result
# => {:column1=>{"2"=>2, "1"=>1}, :column2=>{"3"=>2, "2"=>1}, :column3=>{"1"=>2, "3"=>1}}
There's some room for cleaning up here. The most obvious part is that long, clunky if statement. The test vs nil? is pointless, remember in Ruby the only things that are logically false are false and nil, so since false is never going to show up here, the test vs. nil specifically can be removed.
More than that, though, you're on the right track with the custom Hash.new call, but you don't go far enough. Why not initialize the second tier with zero?
That results in code that looks like:
result = [
{ :column1 => "2", :column2 => "3", :column3 => "1"},
{ :column1 => "2", :column2 => "3", :column3 => "1"},
{ :column1 => "1", :column2 => "2", :column3 => "3"}
]
# Init hash
final_result = Hash.new { |h, k| h[k] = Hash.new(0) }
# Loop result columns
result.each do |single_column|
single_column.each do |r|
final_result[r[0]][r[1]] += 1
end
end
puts final_result.inspect
Have a look at the active record count method (doc link). You can use that in combination with group to do what you are trying to achieve.
[:column1, :column2, :column3].inject({}) do |hash, column|
hash[column] = Model.group(column).count
hash
end

Ruby 1.9 - Convert hash based off regex

Need to convert {"P1" => "ABC", "R1" => "15", "P2" => "LOP", "R2" => "22"}
The hash keys could be in any order.
For instance they could also be {"P1" => "ABC", "R2" => "22", "R1" => "15", "P2" => "LOP"}
or {"R1" => "15", "R2" => "22", "P1" => "ABC", "P2" => "LOP"}
Into this {"ABC" => "15", "LOP" => "22"}
The matcher between keys is the digit.
I'm looking for {P1.value => R1.value, P2.value => R2.value}
P indicating key and R indicating value
The way I'm currently doing it is looping over the initial hash and creating a hash like {1 => 'ABC', 2 => 'LOP'} and also creating {1 => "15", 2 => "22"}.
I then loop over the first new hash and use the key to match the second hash and create the final hash. {"ABC" => "15", "LOP" => "22"}
I'm sure there is a more elegant solution but I just can't think of it.
Check Kernel#Hash. This works for any number of Pn/Rn:
h = {"P1" => "ABC", "R2" => "22", "R1" => "15", "P2" => "LOP"}
Hash[*h.sort_by { |k, v| [k[1..-1].to_i, k[0]] }.map { |k, v| v }]
#=> {"ABC"=>"15", "LOP"=>"22"}
A more orthodox approach without tricks on the order of the keys:
groups = h.group_by { |k, v| k[1..-1].to_i }
Hash[groups.map do |id, pairs|
h2 = Hash[pairs]
h2.values_at("P#{id}", "R#{id}")
end]
#=> {"ABC"=>"15", "LOP"=>"22"}
One more option:
Hash[h.keys.grep(/P\d+/).map {|k| [h[k], h[k.tr('P','R')]] }]
h = {"P1" => "ABC", "R2" => "22", "R1" => "15", "P2" => "LOP"}
Hash[*h.sort_by{|k, _| [k[/\d+/].to_i, k[/\D+/]]}.map(&:last)]

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