Denis S.
Denis S.

Reputation: 471

How can I get specific key values from json?

I need to get all values of 'name' keys and at the same time to get values of 'children' keys. I'm able to retrieve only 'names' from first level but stuck with 'children' since not all 'names' have them.

puts data['labels'].collect { |item| item['name'] }

The JSON response is the following:

{"labels": [{
    "name": "Crime"
}, {
    "name": "Demonstrations"
}, {
    "name": "Music",
    "children": [{
        "name": "Awards"
    }, {
        "name": "Classical"
    }, {
        "name": "Country"
    }, {
        "name": "Other"
    }, {
        "name": "Pop"
    }, {
        "name": "Soul"
    }, {
        "name": "X Factor"
    }]
}, {
    "name": "Politics"
}, {
    "name": "Rescue"
}, {
    "name": "Special Events"
}, {
    "name": "Sports",
    "children": [{
        "name": "Auto Racing"
    }, {
        "name": "Awards"
    }, {
        "name": "Baseball"
    }, {
        "name": "Basketball"
    }, {
        "name": "NASCAR (Cup)"
    }, {
        "name": "NASCAR (Nationwide)"
    }, {
        "name": "NASCAR (Truck)"
    }, {
        "name": "NASCAR (XFINITY)"
    }, {
        "name": "Other"
    }, {
        "name": "Rodeo"
    }, {
        "name": "Rugby"
    }, {
        "name": "Running"
    }, {
        "name": "Sailing"
    }, {
        "name": "Skating"
    }, {
        "name": "Volleyball"
    }]
}, {
    "name": "Traffic"
}, {
    "name": "Weather"
}]}

Upvotes: 0

Views: 99

Answers (2)

Andrey Deineko
Andrey Deineko

Reputation: 52377

puts data['labels'].collect { |item| item['name'] }

Will throw an error

NoMethodError: undefined method `map' for nil:NilClass

since your keys are symbols, not strings.

Also

and at the same time to get values of 'children' keys

Are you sure you want to get keys? Because all keys are identical (:name). May be you need values? Anyway, if you need keys, just change the values to keys in below solution.

Now solution (using safe navigator (&)):

data[:labels].map { |item| [item[:name], item[:children]&.map(&:values)] }
# => [["Crime", nil],
#     ["Demonstrations", nil],
#     ["Music", ["Awards", "Classical", "Country", "Other", "Pop", "Soul", "X Factor"]],
#     ["Politics", nil],
#     ["Rescue", nil],
#     ["Special Events", nil],
#     ["Sports", ["Auto Racing", "Awards", "Baseball", "Basketball", "NASCAR (Cup)", "NASCAR (Nationwide)", "NASCAR (Truck)", "NASCAR (XFINITY)", "Other", "Rodeo", "Rugby", "Running", "Sailing", "Skating", "Volleyball"]],
#     ["Traffic", nil],
#     ["Weather", nil]
#   ]

The above solution without using safe navigator:

data[:labels].map { |item| [item[:name], item[:children] ? item[:children].map(&:values) : nil] }

Upvotes: 2

Cary Swoveland
Cary Swoveland

Reputation: 110755

If h is your hash, you could write

h[:labels].map do |f|
  g = { name: f[:name] }
  f.key?(:children) ? g.merge(children: f[:children].flat_map(&:values)) : g
end
  #=> [{:name=>"Crime"},
  #    {:name=>"Demonstrations"},
  #    {:name=>"Music",
  #     :children=>["Awards", "Classical", "Country", "Other", "Pop", "Soul", "X Factor"]
  #    },
  #    {:name=>"Politics"},
  #    {:name=>"Rescue"},
  #    {:name=>"Special Events"},
  #    {:name=>"Sports",
  #     :children=>["Auto Racing", "Awards", "Baseball", "Basketball", "NASCAR (Cup)",
  #                 "NASCAR (Nationwide)", "NASCAR (Truck)", "NASCAR (XFINITY)", "Other",
  #                 "Rodeo", "Rugby", "Running", "Sailing", "Skating", "Volleyball"]
  #    },
  #    {:name=>"Traffic"},
  #    {:name=>"Weather"}
  #   ]

This uses the methods Hash#key?, Hash#merge, Enumerable#flat_map and a few more common ones.

Upvotes: 1

Related Questions