0

I have the following hash:

{
  "subtype"=>"example subtype",
  "contributors"=> {
    "Concept"=>["Example Contributor", "Example Contributor"],
    "Editor"=>["Example Contributor", "Example Contributor"],
    "Photographer"=>["Example"]
   },
   "publisher"=>"Example Publisher",
   "language"=>"Example Language",
   "dimensions"=>"Example Dimensions"
}

Where one can see that it is a hash of hashes, and some have string values and some have array values. I was wondering how I can iterate through this array so that I could have the following output, for example html:

<h3>example subtype</h3>

<h3>Concept</h3>
<p>Example Contributor, Example Contributor</p>

<h3>Editor</h3>
<p>Example Contributor, Example Contributor</p>

<h3>Photographer</h3>
<p>Example</p>

<h3>Publisher</h3>
<p>Example Publisher</p>

<h3>Language</h3>
<p>Example Language</p>

<h3>Dimensions</h3>
<p>Example Dimensions</p>

So far, I am trying to iterate through the array so following this answer (haml):

- object_details.each do |key, value|
  %h3= key
  - value.each do |v|
    %p= v

Which of course fails immediately as the first item, subtype has no method each as it is not an array.

I would take each value manually, but the hash may change if values are present or absent (for example, publisher or language may not always be present in the hash)

Is there a smart way to iterate through this hash other than checking for the presence of each hash manually?

Community
  • 1
  • 1
waffl
  • 5,179
  • 10
  • 73
  • 123

3 Answers3

2

As @dax mention, and maybe cleaner like:

- object_details.each do |key, value|
  %h3= key
  %p= Array(value).join(', ')

I hope that helps

Correction! I didn't see the nested Hash. You can do something like this(in a helper)

   def headers_and_paragraphs(hash)
     hash.each do |k, v|
       if v.kind_of?(Hash)
         headers_and_paragraphs(v)
       else
         puts "h3: #{k}" # Replace that with content_tag or something similar
         puts "p: #{Array(v).join(', ')}" # Replace that with content_tag or something similar
       end
     end
   end
nronas
  • 181
  • 4
1

you're close. try this:

- object_details.each do |key, value|
  %h3= key
  - if value.kind_of?(Array)
    -value.each do |v|
      %p= v
  - else
    %p= v
dax
  • 10,779
  • 8
  • 51
  • 86
  • Also need to check for value.kind_of?(Hash) – Some Guy Jul 10 '14 at 13:18
  • @SomeGuy Having just the data from the question the test for Array would be enough in this case. (Note that OP wants only iterate over the `contributors` sub-hash) However, thanks for your comment below my - deleted - answer.. It makes not much sense anymore here since this one will already do it.. +1 – hek2mgl Jul 10 '14 at 13:24
1
$modifiedContent = []
def convert(hash)
   hash.each do |key, value|
      unless (value.kind_of?(Hash))
         unless (value.is_a? String and hash.first.first.eql? key and hash.first.last.eql? value)
            $modifiedContent << "<h3>#{key}</h3>"
            $modifiedContent << "<p>#{Array(value).join(', ')}</p>"
         else
            $modifiedContent << "<p>#{value}</p>"
         end
      else
         convert(value)
      end
      $modifiedContent << ""
   end
end

myHash = {
  "subtype"=>"example subtype",
  "contributors"=> {
    "Concept"=>["Example Contributor", "Example Contributor"],
    "Editor"=>["Example Contributor", "Example Contributor"],
    "Photographer"=>["Example"]
   },
   "publisher"=>"Example Publisher",
   "language"=>"Example Language",
   "dimensions"=>"Example Dimensions"
}

convert(myHash)
puts $modifiedContent
MIZ
  • 385
  • 1
  • 14