Incrementing json value of a key in ruby?

Viewed 57

I'm looking for a way to increment the values of keys foo and bar

{
  "users": [
    {
      "foo": 6522
    },
    {
      "bar": 20
    }
  ]
}

Here is an example of what I attempted, however the result leaves the values unchanged.

data = JSON.parse(filepath\info.json)

puts data["users"][1].values[0] # 20

data["users"][1].values[0] += 5

puts data["users"][1].values[0] # remains 20, but expected 25

Is there another way to increment these values?

2 Answers

You'll need to know the key to increment in the user. Since it looks like it's different some times, you can achieve this with 2 eachs

data[:users].each {|u| u.keys.each {|k| u[k] += 1 } }

Iterate over the users, then iterate over the keys in the user object, adding 1.

This assumes only one key is in users and it's an integer.

values returns a new array so you won't be able to use it that way.

Using Hash#transform_values!

There are a number of ways to do this, but since you already have the data structure as a Hash, the one that seems most natural to me is using Hash#transform_values! for in-place modification of the Integers stored as Hash values. Consider the following example, which iterates over the Hash objects inside the Array stored in hash[:users] and increments each value:

hash = {:users=>[{:foo=>6522}, {:bar=>20}]}
hash[:users].map { |h| h.transform_values! { |v| v += 1 } }
#=> [{:foo=>6523}, {:bar=>21}]

# @note The changes to your Hash values are made in-place, and
#   are persistent.
hash
#=> {:users=>[{:foo=>6523}, {:bar=>21}]}

Caveats to Consider

Of course, this approach only works if you know that :users is your top-level Hash key, and that it contains an Array of Hash objects that each have Integer values. If your data structure isn't consistent, or you can't rely on the Hash values in the Array being Integers, then you might need to take a more complex and/or defensive approach by recursing or pattern matching through your data structure, and then validatingyour Hash values are Integers (or casting them as such) before attempting to increment them.

The solution I provide above works with your posted example, but definitely makes some basic assumptions. If they're safe assumptions for your data, then give it a whirl!

Related