I have a bit of a problem with MongoDB in that it returns hashes with the keys in double quotes and integers as floats all the time, has this been a problem for anyone else?
for examples after a map reducing or grouping, say I have a bunch of hashes which look like this:
{"unknown"=>54.0, "pedestrians"=>572.0, "vehicles"=>1045.0}
But what I really want is:
{ unknown: 54, pedestrians: 572, vehicles: 1045 }
Any ideas on how I can easily convert it?
Each key can only have one value. But the same value can occur more than once inside a Hash, while each key can occur only once.
Iterating over a Hash You can use the each method to iterate over all the elements in a Hash. However unlike Array#each , when you iterate over a Hash using each , it passes two values to the block: the key and the value of each element.
In Ruby, the values in a hash can be accessed using bracket notation. After the hash name, type the key in square brackets in order to access the value.
When we iterate over a hash, the #each method (as well as any other iteration method you use) yields the key/value pair together into the block. Inside that block, you have access to the key and the value, and can manipulate either one or both. Inside the iteration we have access to both the key and the value.
You could do:
original = {"unknown"=>54.0, "pedestrians"=>572.0, "vehicles"=>1045.0}
converted = Hash[ original.map { |key, value| [key.to_sym, value.to_i] } ]
Or if you're using Rails, you could make it a HashWithIndifferentAccess
and just convert the values:
original = HashWithIndifferentAccess.new(original)
original.each { |key, value| original[key] = value.to_i }
In order to handle all possible key types correctly, if you are going to convert it I would suggest something like:
h = {:a => 54.0, :b => 572.0, :c => 1045.0, :d => 'test', :e => 1.23 }
p(h.merge(h) do |k, v|
v = v.to_i if v.is_a?(Float) && v.to_i == v
v
end)
The above code will convert Float values in a hash that are actually integral to Integer.
But you actually don't need to do this at all. While it's common to distrust the floating point formats, it turns out that they do represent integral values exactly.
You can trust that any value that was an integer in the database will compare exactly with integer constants (including 0) and that you will not see any rounding artifacts.
You will notice a difference, of course, if you divide a float by something other than a factor.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With