Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I have a nested Hash like this :
{
:a=>{
:toto=>{
:foo=>10,
:bar=>11,
:baz=>12
},
:titi=>"a"
},
:b=>{
:toto=>{
:foo=>31,
:bar=>45,
:baz=>78
},
:titi=>"b"
}
}
My goal is to sum all the :baz values. I'm sure there is a beautiful way to do this in ruby. Any idea?
Thanks.
#inject is very powerful method that works for both arrays and hashes. You can walk through values of hash and sum the needed key to the total sum.
hash.inject(0) { |sum, (_,v)| sum += v[:toto][:baz] } # => 90
h = {
:a=>{
:toto=>{
:foo=>10,
:bar=>11,
:baz=>12
},
:titi=>"a"
},
:b=>{
:toto=>{
:foo=>31,
:bar=>45,
:baz=>78
},
:titi=>"b"
}
}
h.inject(0){|sum,(_,v)| sum +=v.fetch(:toto,{}).fetch(:baz,0)}
This method finds all :baz elements, regardless of their path.
h = {
:a=>{
:toto=>{
:foo=>10,
:bar=>11,
:baz=>12,
},
:titi=>"a"
},
:b=>{
:toto=>{
:foo=>31,
:bar=>45,
:baz=>78,
},
:titi=>"b",
},
}
def sum_baz(hash)
hash.values.reduce(0) do |memo, elem|
if elem.is_a?(Hash)
memo += sum_baz(elem)
memo += elem[:baz] if elem[:baz]
end
memo
end
end
sum_baz(h) # => 90
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I have a structure defined in 'strct'. Its possible to add some ruby code like the next example?
def strct(i)
{
"mwdata": [
i.times do //incorrect
{
"mwtype": "cell",
"mwsize": [
1,
3
],
"mwdata": [
10,
23,
199
]
}
end //incorrect
]
}
end
You can multiply arrays by using *, but this will create an Array of references to the same Hash object, changing one, changes all of them. (as #mudasobwa pointed out in the comments)
def strct(i)
{ "mwdata": [ {...} ] * i }
end
It's also possible to use tap:
def strct(i)
{ "mwdata" => [].tap do |array|
i.times do
array << { .... }
end
end
}
end
Or inject:
def strct(i)
{ "mwdata" => 1.upto(i).inject([]) do |array|
array << { .... }
end
}
end
Note
I understand the reason for this question, as I have often found myself doing something like:
def strct(i)
result = { "foo" => [] }
i.times do
result["foo"] << "Something #{i}"
end
result
end
Quick googling gave me this: hash_builder.rb that works like jsonbuilder and can be used to create hash "templates".
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I want to find out what's the first, the second, and the third result, so that I can do if firstnumber==secondnumber && secondnumber==thirdnumber. How could I find those numbers on the results?
numbers = 3.times.map { Random.new.rand(0..10000) }
prizes = numbers.map do |x|
case x
when 1..3000
[ '7', 10000 ]
when 3001..6000
[ "Cherries", 500 ]
when 6001..10000
[ "Diamond", 400 ]
end
end
puts "Your results are: #{prizes.collect { |p| p[0] }.join(", ")}!
I tried to use p[0][0], but it gives the first letter instead.
Say if:
results = prizes.collect { |p| p[0] } #=> ["Diamond", "Cherries", "7"]
Then do the following to get at each result:
results[0] #=> "Diamond"
results[1] #=> "Cherries"
results[2] #=> "7"
You could also use results.first to get the first element. If you happen to be working in Rails you can even do the following:
results.second #=> "Cherries"
results.third #=> "7"
Here's a fine way to do this:
numbers = 3.times.map { Random.new.rand(0..10000) }
prizes = numbers.map do |x|
case x
when 1..3000
{ name: '7', val: 10000 }
when 3001..6000
{name: "Cherries", val: 10000 }
when 6001..10000
{name: "Diamond", val: 400 }
end
end
# You could replace 'map' with 'collect' here and have the same results
prizes_string = prizes.map { |p| "#{p[:name]}: #{p[:val]}" }.join(" and ")
puts "Your results are: #{prizes_string}!"
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 7 years ago.
Improve this question
How to sum up values from all hashes more elegantly than I do it?
boards_statistics array contains items_info hashes.
def generate_accumulated_statistics(boards_statistics)
# Create hash with zero values - its purprose is to
# accumulate results from all other hashes
resulted_hash = {
items_info: {
finished_items: {
todo: 0,
in_progress: 0,
done: 0
},
hours_worked: {
estimated: 0,
time_logged: 0
},
story_points_completed: {
estimated: 0,
completed: 0
},
due_today_items: 0,
late_items: 0
},
team_info: []
}
boards_statistics.each do |statistics|
resulted_hash[:items_info][:finished_items][:todo] += statistics[:items_info][:finished_items][:todo]
resulted_hash[:items_info][:finished_items][:in_progress] += statistics[:items_info][:finished_items][:in_progress]
resulted_hash[:items_info][:finished_items][:done] += statistics[:items_info][:finished_items][:done]
resulted_hash[:items_info][:hours_worked][:estimated] += statistics[:items_info][:hours_worked][:estimated]
resulted_hash[:items_info][:hours_worked][:time_logged] += statistics[:items_info][:hours_worked][:time_logged]
resulted_hash[:items_info][:story_points_completed][:estimated] += statistics[:items_info][:story_points_completed][:estimated]
resulted_hash[:items_info][:story_points_completed][:completed] += statistics[:items_info][:story_points_completed][:completed]
resulted_hash[:items_info][:due_today_items] += statistics[:items_info][:due_today_items]
resulted_hash[:items_info][:late_items] += statistics[:items_info][:late_items]
end
end
You can implement your own flavor of deep merging. Here:
class ::Hash
def deep_merge(second)
merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : (v1+v2) }
self.merge(second, &merger)
end
end
resulted_hash
# => {:items_info=>{:finished_items=>{:todo=>0, :in_progress=>0, :done=>0}, :hours_worked=>{:estimated=>0, :time_logged=>0}, :story_points_completed=>{:estimated=>0, :completed=>0}, :due_today_items=>0, :late_items=>0}, :team_info=>[]}
boards_statistics
# => {:items_info=>{:finished_items=>{:todo=>1, :in_progress=>1, :done=>1}, :hours_worked=>{:estimated=>1, :time_logged=>1}, :story_points_completed=>{:estimated=>1, :completed=>1}, :due_today_items=>1, :late_items=>1}, :team_info=>[]}
resulted_hash = resulted_hash.deep_merge(boards_statistics)
# => {:items_info=>{:finished_items=>{:todo=>1, :in_progress=>1, :done=>1}, :hours_worked=>{:estimated=>1, :time_logged=>1}, :story_points_completed=>{:estimated=>1, :completed=>1}, :due_today_items=>1, :late_items=>1}, :team_info=>[]}
resulted_hash = resulted_hash.deep_merge(boards_statistics)
# => {:items_info=>{:finished_items=>{:todo=>2, :in_progress=>2, :done=>2}, :hours_worked=>{:estimated=>2, :time_logged=>2}, :story_points_completed=>{:estimated=>2, :completed=>2}, :due_today_items=>2, :late_items=>2}, :team_info=>[]}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I'm trying to remove key-value pairs from a hash whose value is less than the highest key-value pair's value in the hash. Example: If my hash is {:Jan => 3, :Feb =>4, :Mar =>4}, I'd want to remove the :Jan => 3 entry. I am attempting delete_if with a comparison to no avail.
def highestvalue(myhash)
myhash.delete_if { |k,v| v < v}
print myhash
end
months = {:Jan => 3, :Feb =>4, :Mar =>4}
highestvalue(months)
def highestvalue(myhash)
max = myhash.values.max
myhash.delete_if { |k, v| v < max }
end
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
This:
(0..8).each do |n|
"a_#{n}" = {}
end
gives me an error "syntax error, unexpected '=', expecting keyword_end". I wanted to create a_0 = {}, a_1 = {}, a_2 = {} etc.
I think you want an array of hashes.
a = []
(0..8).each do |n|
a[n] = {}
end
Result:
a #=> [{}, {}, {}, {}, {}, {}, {}, {}, {}]
a[0] #=> {}
a[1] #=> {}
...etc...
although depending on what you need to do next, this type of initialization may not be necessary.
binding.instance_eval do (0..8).each do |i|
local_variable_set("a_#{i}", {})
...
end end
Without bad magic, you won't get the functionality you want (there are ways to do that but they are bad and hacky). Use a hash or array instead.