zw963
December 31, 2024, 11:22am
1
Following is a example:
h2 = Hash(String, Array(Time::Span)).new([] of Time::Span)
# h2["foo"] = h2["foo"].dup unless h2.has_key?(key)
h2["foo"] << 1.second
pp h2 # => {}
pp h2.keys # => []
pp h2["foo"] # => [00:00:01]
When pp on h2, there is no key “foo” exists, but, when visit it use h2["foo"]
, i get the correct result, what i expected is, the key “foo” exists after the code h2["foo"] << 1.second
is run.
The workaround is, uncomment the line h2["foo"] = h2["foo"].dup
, but it’s wired to add a code like this, my current usage need run h2["foo"] << 1.second
even on a empty hash no error, did I do something wrong?
Sunrise
December 31, 2024, 2:20pm
2
This has been explained in the document.
API doc
As an alternative, you can use h2["foo"] += [1.second]
3 Likes
zw963
January 3, 2025, 5:23am
4
I do a benchmark on all known working solution, @Blacksmoke16 solution is the best on runtime and memory usage
code
require "benchmark"
def meth1
h2 = Hash(Int32, Array(Time::Span)).new([] of Time::Span)
(1..1000000).each do |e|
h2[e] = h2[e].dup unless h2.has_key?(e)
h2[e] << e.seconds
end
end
def meth2
h2 = Hash(Int32, Array(Time::Span)).new([] of Time::Span)
(1..1000000).each do |e|
h2[e] += [e.seconds]
end
end
def meth3
h2 = Hash(Int32, Array(Time::Span)).new() { |h, k| h[k] = [] of Time::Span }
(1..1000000).each do |e|
h2[e] << e.seconds
end
end
Benchmark.ips do |x|
x.report("meth1") { meth1 }
x.report("meth2") { meth2 }
x.report("meth3") { meth3 }
end
puts Benchmark.memory { meth1 }
puts Benchmark.memory { meth2 }
puts Benchmark.memory { meth3 }
╰──➤ $ cr run --release 1.cr
meth1 7.31 (136.75ms) (±17.06%) 139MB/op 1.41× slower
meth2 8.41 (118.96ms) (±11.45%) 170MB/op 1.23× slower
meth3 10.32 ( 96.89ms) (± 9.33%) 139MB/op fastest
146073600
178070928
146068608