1

first time posting here. Having trouble getting into a JSON, and I could use some active.

The data that I need is at this level:

restaurant["menu"][0]["children"][0]["name"]

restaurant["menu"][0]["children"][0]["id"]

I want an array of "id"s based on "name"s.

This is the method that I'm working with:

def find_burgers(rest)

    array = []

    rest["menu"].each do |section| 
    section["children"].each do |innersection| 
    innersection["name"].downcase.split.include?("burger")
    array.push(innersection["id"]) 
    end
  end   
  return array
end

As you can imagine, I'm getting back an array of every "id", not just the "id"s for burgers. I've tried many combinations of .map and .keep_if.

Thanks for reading.

EDIT: This is one menu item:

{
    "children" => [
    [ 0] {
        "availability" => [
            [0] 0
        ],
            "children" => [
            [0] {
                             "children" => [
                    [0] {
                        "availability" => [
                            [0] 0
                        ],
                             "descrip" => "",
                                  "id" => "50559491",
                        "is_orderable" => "1",
                                "name" => "Single",
                               "price" => "0.00"
                    },
                    [1] {
                        "availability" => [
                            [0] 0
                        ],
                             "descrip" => "",
                                  "id" => "50559492",
                        "is_orderable" => "1",
                                "name" => "Double",
                               "price" => "2.25"
                    }
                ],
                              "descrip" => "What Size Would You Like?",
                    "free_child_select" => "0",
                                   "id" => "50559490",
                         "is_orderable" => "0",
                     "max_child_select" => "1",
                "max_free_child_select" => "0",
                     "min_child_select" => "1",
                                 "name" => "Milk Burger Size"
            },
            [1] {
                             "children" => [
                    [0] {
                        "availability" => [
                            [0] 0
                        ],
                             "descrip" => "",
                                  "id" => "50559494",
                        "is_orderable" => "1",
                                "name" => "Bacon",
                               "price" => "2.00"
                    }
                ],
                              "descrip" => "Add",
                    "free_child_select" => "0",
                                   "id" => "50559493",
                         "is_orderable" => "0",
                     "max_child_select" => "1",
                "max_free_child_select" => "0",
                     "min_child_select" => "0",
                                 "name" => "Burgr Ad Bacon Optn"
            }
        ],
             "descrip" => "American cheese, lettuce, tomato and Milk Sauce",
                  "id" => "50559489",
        "is_orderable" => "1",
                "name" => "Milk Burger",
               "price" => "4.25"
    },
2
  • Can you also post the JSON/parsed hash? Commented Nov 21, 2014 at 3:39
  • I'll post one above. Commented Nov 21, 2014 at 4:22

3 Answers 3

3

In general, you can iterate through a nested hash like this:

def iterate(h)
  h.each do |k, v| 
    if v.is_a?(Hash) || v.is_a?(Array)
      iterate(v)
    else
      puts("k is #{k}, value is #{v}")
    end
  end
end

But since you have the concrete, hardcoded names children, name, etc, it seems there's only way to do that is the way you're doing it.

Sign up to request clarification or add additional context in comments.

Comments

2

A little more accurate answer that iterates over Hashes or Arrays in JSON

j = {'key$1' => 'asdada',
     'key$2' => ['key$3' => 2,
                 'key$4' => 's',
                 'key$6' => ['key$7' => 'man',
                             'key$8' => 'super']
                 ],
     'key5' => 5 }

def iterate(i)
  if i.is_a?(Hash)
    i.each do |k, v|
      if v.is_a?(Hash) || v.is_a?(Array)
        puts("k is #{k}, value is #{v}")
        iterate(v)
      else
        puts("k is #{k}, value is #{v}")
      end
    end
  end
  if i.is_a?(Array)
    i.each do |v|
      iterate(v)
    end
  end
end

iterate(j)

Comments

1

You're performing a test to see if the name contains "burger" but you're not doing anything with the result of the test. Try this instead:

def find_burgers(rest)

  array = []

  rest["menu"].each do |section| 
    section["children"].each do |innersection| 
      array.push(innersection["id"]) if innersection["name"].downcase.split.include?("burger")
    end
  end   
  return array
end

Also, consider using a regular expression instead of the `downcase.split.include?' like so:

def find_burgers(rest)

  array = []

  rest["menu"].each do |section| 
    section["children"].each do |innersection| 
      array.push(innersection["id"]) if innersection["name"] =~ /\bburger\b/i
    end
  end   
  return array
end

The regular expression returns true if the name contains the string "burger" surrounded by word-breaks (\b) ignoring case (/i).

And finally (I think) you could use a more functional approach like so:

def find_burgers(rest)
  rest["menu"].map do |section| 
    section["children"].select do |innersection| 
      innersection["name"] =~ /\bburger\b/i
    end
  end.flatten.map {|item| item["id"] }
end

The select returns only those items that match the regular expression, the first map passes back an array of matching innersections for each section, the flatten turns the array of arrays into a simple array, and the final map picks out just the id from each innersection.

I think I've gone too far.

2 Comments

That did it! I'm new to writing code, and I spent (wasted?) of time on this, so I really appreciate it.
Cool! Keep at it -- it gets easier. And please consider accepting my answer if it's what you needed.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.