Reputation: 21025
I need a hash with one key per wday hour minute. I wrote this:
result = {}
for wday in 1..7 do
result[wday] = {}
for hour in 0..23 do
result[wday][hour] = {}
for minute in 0..59 do
result[wday][hour][minute] = 0
end
end
end
I wanted to know if there is a better way to achieve the same behavior with less lines of code, and be as readable as is.
Upvotes: 1
Views: 88
Reputation: 173612
It's not the prettiest of the lot, but here's something to consider:
(1..7).to_a.product((0..23).to_a, (0..59).to_a).
reduce({}) do |hash, (weekday, hour, minute)|
hash.tap { |h| ((h[weekday] ||= {})[hour] ||= {})[minute] = 0 }
end
Upvotes: 1
Reputation: 110695
I would do it thusly, which is merely a refinement of what the OP has written.
result = (1..7).each_with_object({}) do |wday, f|
f[wday] = (0..23).each_with_object({}) do |hour, g|
g[hour] = (0..59).each_with_object({}) do |minute, h|
h[minute] = 0
end
end
end
Alternatively,
result = (1..7).each_with_object({}) do |wday, f|
(0..23).each_with_object(f[wday] = {}) do |hour, g|
(0..59).each_with_object(g[hour] = {}) do |minute, h|
h[minute] = 0
end
end
end
Upvotes: 0
Reputation: 103
You can use a more readable set of instructions like this:
result = {}
(1..7).each do |wday|
(0..23).each do |hour|
(0..59).each do |minute|
result[wday] ||= {}
result[wday][hour] ||= {}
result[wday][hour][minute] = 0
end
end
end
Even if there are more powerful solutions, I think that this is more readable if you don't need a more complex behaviour.
Upvotes: 0
Reputation: 13487
You can use default procs as possible way:
hash = Hash.new do |h, k|
h[k] = Hash.new do |h1, k1|
h1[k1] = Hash.new do |h2, k2|
h2[k2] = 0 if (0..59).include?(k2)
end if (0..23).include?(k1)
end if (1..7).include?(k)
end
Then check:
hash[1][2][3]
#=> 0
hash[1][2][300]
#=> nil
The main advantage of this solution is that you don't need to create a bunch of objects, you just create a rule. Creating objects is possible if you have a little amount of objects like in your instance, but could be a problem if you want to create a lot of them.
Upvotes: 4
Reputation: 845
Could you try this one:
(1..7).inject({}) do |wday, i|
wday[i] = (0..23).inject({}) do |hour, j|
hour[j] = (0..59).inject({}) do |minute, k|
minute[k] = 0
minute
end
hour
end
wday
end
or something like that:
Hash.new(Hash.new(Hash.new(0))
which define default constructors for your nested hash properly
Upvotes: 0