0

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"
}]}

2 Answers 2

2
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] }
Sign up to request clarification or add additional context in comments.

2 Comments

Andrey, p data['labels'].collect { |item| item['name'] } doesn't throw an error for me it just grabs values of all 'name' but ignores 'name' that are related to 'children'. I'm on ruby 2.1.2 and safe navigation operator isn't supported in my case(((
Thank you, Andrey!That's exactly what i was trying to get!
1

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.

3 Comments

Thanks Cary, but unfortunately I'm on ruby 2.1.2 and safe navigation operator is not supported in my case(((
Denis, I didn't use the safe navigation operator. Perhaps you intended your comment for @Andrey.
oooops, my bad Cary.You are right)I appreciate your answer)Thank you

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.