user1971993
user1971993

Reputation:

Looping through Hash(Array)

I have this problem, where I keep on getting

TypeError: can't convert String into Integer

This is where I'm going through this @data object.

here is the @data object

@data = HTTParty.get("")

{
"body"=>{
    "predictions"=>{
        "direction"=>{
            "prediction"=>[
                {
                    "epochTime"=>"1362931090892",
                },
                {
                    "epochTime"=>"1362931747892",

                },
                {
                    "epochTime"=>"1362932467892",

                },
                {
                    "epochTime"=>"1362933187892",

                },
                {
                    "epochTime"=>"1362933847892",

                }
            ],
            "title"=>"xxxx"
        },
        "a"=>"xx",
        "b"=>"x"
    },
    "name"=>"some"
}

}

and my code to go through above has been

  <%  if @data["body"]["predictions"].present? %>
  <% @data["body"]["predictions"].each do |p| %>
        <%p["direction"].each do |d|%>
            <% d["prediction"].each do |k|%>
              <h4><%= k["epchoTime.."] %> </h4>
            <%end%>
        <%end%>
      <%end%>
<%end%>

I have no idea how to go through this, I assume this is due to the fact I should access stuff like I do in C++ with name[integer] value, but I would like to use ["name"]. How can I make my code work ?

Thanks for your precious time and consideration.

Upvotes: 0

Views: 313

Answers (4)

the Tin Man
the Tin Man

Reputation: 160631

Here's an example, using Nokogiri, of parsing the raw XML:

require 'nokogiri'

doc = Nokogiri::XML(<<EOT)
<body>
  <predictions>
    <direction>
      <prediction>
        <epochTime>1362931090892</epochTime>
        <epochTime>1362931747892</epochTime>
        <epochTime>1362932467892</epochTime>
        <epochTime>1362933187892</epochTime>
        <epochTime>1362933847892</epochTime>
      </prediction>
      <title">xxxx</title>
      <a>"xx"</a>
      <b>"x"</b>
      <name>"some"</name>
    </direction>
  </predictions>
</body>
EOT

epoch_times = doc.search('epochTime').map(&:text)

Which returns an array of epochTime values:

[
    [0] "1362931090892",
    [1] "1362931747892",
    [2] "1362932467892",
    [3] "1362933187892",
    [4] "1362933847892"
]

Sometimes we need to loop through all prediction blocks containing the epochTime blocks. This will do it:

epoch_times = doc.search('prediction').map{ |predict|
  predict.search('epochTime').map(&:text)
}

[
    [0] [
        [0] "1362931090892",
        [1] "1362931747892",
        [2] "1362932467892",
        [3] "1362933187892",
        [4] "1362933847892"
    ]
]

Sometimes you need to find a particular node and grab all the elements of a certain type inside it:

doc = Nokogiri::XML(<<EOT)
<body>
  <predictions>
    <direction>
      <prediction id="1">
        <epochTime>1362931090892</epochTime>
        <epochTime>1362931747892</epochTime>
        <epochTime>1362932467892</epochTime>
        <epochTime>1362933187892</epochTime>
        <epochTime>1362933847892</epochTime>
      </prediction>
      <title">xxxx</title>
      <a>"xx"</a>
      <b>"x"</b>
      <name>"some"</name>
    </direction>
  </predictions>
</body>
EOT

epoch_times = doc.search('prediction[id="1"]').map{ |predict| predict.search('epochTime').map(&:text) }

[
    [0] [
        [0] "1362931090892",
        [1] "1362931747892",
        [2] "1362932467892",
        [3] "1362933187892",
        [4] "1362933847892"
    ]
]

Upvotes: 1

user1971993
user1971993

Reputation:

The whole hash things was getting out of hand as I had constantly detect each one's present and loop through it, so As Tin man suggested, I used XML 'nokogiri' and then used .css method to detect if it existed and looped through it, since original response was in xml.

  @doc.css('predictions').each do |predictions_node| 
        predictions_node.css('direction').each do |direction_node| 
          direction_node.css('prediction').each do |prediction|
            // stuff here 

Thanks for your time and consideration.

Upvotes: 0

Paritosh Piplewar
Paritosh Piplewar

Reputation: 8132

Looks like you are ignoring the keys which don't have nested values say title and a , b .

        "title"=>"xxxx"
    },
    "a"=>"xx",
    "b"=>"x"
},

Your final code should look like

if @data["body"]["predictions"].present? 
 @data["body"]["predictions"].each do |p|
  p.each do |d|
   if d.kind_of? Hash
    d.each do |k| 
     if k.kind_of? Array
      k.each do |x|
        if x.kind_of? Array
          x.each do |y|
            if y.kind_of? Hash
              puts y["epochTime"]
            end
          end
        end
      end 
    end
    end
   end
  end
 end
end

The above code is ugly but you are C++ programmmer , you might like it :P

Upvotes: 0

dasnixon
dasnixon

Reputation: 998

the Tin Man has a good point about keeping this logic outside the view, and should be a work of a model. Here is a cleaner view though.

<% @data['body']['predictions']['direction']['prediction'].each do |x| %>
  <% x.each do |k, v| %>
    <h4><%= v %></h4>
  <% end %>
<% end %>

Upvotes: 0

Related Questions