Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

join all elements in array reference by hash

by johnko (Initiate)
on Dec 29, 2012 at 20:07 UTC ( #1010848=perlquestion: print w/ replies, xml ) Need Help??
johnko has asked for the wisdom of the Perl Monks concerning the following question:

O wise and learned monks of the perl (and particularly Christian persuasion), I seek wisdom on how to join all the elements of my array that I've referenced in a hash. I've parsed out sections of a text bible into a structure that I reference by book, chapter, and verse. I have tried to save my results to a hash that looks like:
... my @saved_verses = @verses; $bible{$book}{$chapter}{'verses'} = \@saved_verses; @verses = (); # use again for next chapter
which I try to subsequently access to get either individual verses out, or to print all the verses in a particular chapter. 2 questions: 1. Is this the right way to copy off the @verses array so that I can reuse it when parsing the next chapter? or will I have the same problem with @saved_verses being replaced with the new verses? 2. When trying to access all the verses of a particular chapter, how do I join all the verses? (i.e. I want all the verses in Genesis Chapter 1) I seem to be able to access individual verses but can't seem to join on the array:
my $n = 0; $bible{$bookname}{$chapter}{'verses'}[$n]; # but neither of the following seem to work join("\n\n",$bible{$bookname}{$chapter}{'verses'}[0..$#{$bible{"$b +ookname"}{"$chapter"}{'verses'}}]); join("\n\n",$bible{$bookname}{$chapter}{'verses'}); # I get instead ARRAY(0x[0-9]*) or Argument "" isn't numeric in ar +ray element at ...
Hoping for a revelation on the proper procedures.

Comment on join all elements in array reference by hash
Select or Download Code
Re: join all elements in array reference by hash
by toolic (Chancellor) on Dec 29, 2012 at 20:15 UTC
    Did you try to dereference your array ref?
    join("\n\n", @{ $bible{$bookname}{$chapter}{'verses'} });

    Do you realize that you are discarding the string returned by join?

    See also:

      I'll look at the perldsc. I had a print in front of the join before and had also tried to set it to a value, which I later printed. Had only included the snippet that I thought mattered. Thanks.
Re: join all elements in array reference by hash
by 2teez (Priest) on Dec 29, 2012 at 21:37 UTC

    Hi johnko,

    "..Is this the right way to copy off the @verses array so that I can reuse it when parsing the next chapter? or will I have the same problem with @saved_verses being replaced with the new verses?.."

    I don't know how your data comes, but something like this could give a head up.

    use warnings; use strict; my %bible; my $book; my $chapter; while (<DATA>) { chomp; if ( /^[^0-9]/ and !/chapter/i ) { $book = $_; } elsif (/chapter/i) { $chapter = $_; } else { my ( $verse, $words ) = split /\s/, $_, 2; push @{ $bible{$book}{$chapter}{$verse} }, $words; } } use Data::Dump; dd \%bible; __DATA__ Genesis chapter 1 1 In the beginning God created the heavens and the earth. 2 The earth was without form, and void; and darkness was on the face o +f the deep. And the Spirit of God was hovering over the face of the w +aters. chapter 2 1 Thus the heavens and the earth, and all the host of them, were finis +hed. 2 And on the seventh day God ended His work which He had done, and He +rested on the seventh day from all His work which He had done. Exodus chapter 1 1 Now these are the names of the children of Israel who came to Egypt; + each man and his household came with Jacob: 2 Reuben, Simeon, Levi, and Judah; Matthew chapter 1 1 The book of the genealogy of Jesus Christ, the Son of David, the Son + of Abraham: 2 Abraham begot Isaac, Isaac begot Jacob, and Jacob begot Judah and hi +s brothers. John chapter 1 1 In the beginning was the Word, and the Word was with God, and the Wo +rd was God. 2 He was in the beginning with God.
    Output:
    { Exodus => { "chapter 1" => { 1 => [ "Now these are the names of the children of Is +rael who came to Egypt; each man and his household came with Jacob:", ], 2 => ["Reuben, Simeon, Levi, and Judah;"], }, }, Genesis => { "chapter 1" => { 1 => ["In the beginning God created th +e heavens and the earth."], 2 => [ "The earth was without form, an +d void; and darkness was on the face of the deep. And the Spirit of G +od was hovering over the face of the waters.", ], }, "chapter 2" => { 1 => [ "Thus the heavens and the earth +, and all the host of them, were finished. ", ], 2 => [ "And on the seventh day God end +ed His work which He had done, and He rested on the seventh day from +all His work which He had done.", ], }, }, John => { "chapter 1" => { 1 => [ "In the beginning was the Word, and the Word w +as with God, and the Word was God.", ], 2 => ["He was in the beginning with God."], }, }, Matthew => { "chapter 1" => { 1 => [ "The book of the genealogy of Jesus Christ, th +e Son of David, the Son of Abraham:", ], 2 => [ "Abraham begot Isaac, Isaac begot Jacob, and J +acob begot Judah and his brothers.", ], }, }, }
    Which gives us what we want, each book, each chapter and its verses.
    Then knowing, the chapter and verses we want and using the wisdom of toolic we can access what we want.
    All things been equal, let say we want to see all the verses in Genesis, chapter 1.
    Let cheat a bit, like so:
    # a form of toolic wisdom for ( sort { $a <=> $b } keys %{ $bible{'Genesis'}{'chapter 1'} } ) { +# updated print $_, ": ", @{ $bible{'Genesis'}{'chapter 1'}{$_} }, $/; }
    Output:
    1: In the beginning God created the heavens and the earth. 2: The earth was without form, and void; and darkness was on the face +of the deep. And the Spirit of God was hovering over the face of the +waters.
    Please check the reference initially stated above perldsc

    If you tell me, I'll forget.
    If you show me, I'll remember.
    if you involve me, I'll understand.
    --- Author unknown to me
      for ( keys %{ $bible{'Genesis'}{'chapter 1'} }) { print $_, ": ", @{ $bible{'Genesis'}{'chapter 1'}{$_} }, $/; }

      That this loop prints your example data in the correct order is an artifact of the small number of verses in the data. Try adding the verses
          3 Three.
          4 Four.
          ...
          10 Ten.
      to Genesis Chapter 1 and you will see the verses printed in apparently random order (really, the hashing order). Numerically sort the 'verse' keys before printing to get the correct order. (Tested.)

      for (sort { $a <=> $b } keys %{ $bible{'Genesis'}{'chapter 1'} }) { print $_, ": ", @{ $bible{'Genesis'}{'chapter 1'}{$_} }, $/; }

      Also, I would question your departure from the array-based nature of verse storage in the first place. johnko's OP example implies that each string/line is a verse and is stored in an array in verse order, and this is the way toolic's reply treats it. In your example, you store one and only one verse per anonymous array with the verse number as the hash key to the array, which seems a bit wasteful and, more importantly, potentially rather confusing. Are there, in fact, 'verses' that consist in more than one line of data?

      I would also question how your book/chapter/verse parsing would handle books like "1 Corinthians", "2 Thessalonians", etc., but, as you say, this is all critically dependent on the exact format of the data johnko is parsing, which is not revealed to us.

        • "..Numerically sort the 'verse' keys before printing to get the correct order..."

          Agreed 100%. Original POST corrected.
        • "..I would question your departure from the array-based nature of verse storage in the first place.."

          Reference for each of the verses separately informed that decision of mine.
          If I have done, like so:
          ... else { push @{ $bible{$book}{$chapter}{'verses'} }, $_; }
          Then output would have been like so:
          "Genesis" => { "chapter 1" => { verses => [ "1 In the beginning God created the heavens and + the earth.", "2 The earth was without form, and void; and da +rkness was on the face of the deep. And the Spirit of God was hoverin +g over the face of the waters.", ], }, "chapter 2" => { verses => [ "1 Thus the heavens and the earth, and all the +host of them, were finished. ", "2 And on the seventh day God ended His work wh +ich He had done, and He rested on the seventh day from all His work w +hich He had done.", ], }, },
          which ofcourse is cool and probably faster [ not tested though ]. But I thought, what if we decides to refer to each of the verses?
        • "..I would also question how your book/chapter/verse parsing would handle books like "1 Corinthians", "2 Thessalonians", etc.,.."

          One can of course use the roman numbering like "1 Corinthians", "2 Thessalonians" would then be "I Corinthians", "II Thessalonians", "III John", etc

        Finally, like I said in mine OP and you rightly pointed out this is all critically dependent on the exact format of the data johnko is parsing, which is not revealed to us

        If you tell me, I'll forget.
        If you show me, I'll remember.
        if you involve me, I'll understand.
        --- Author unknown to me

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1010848]
Approved by toolic
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others romping around the Monastery: (12)
As of 2014-12-22 21:43 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (131 votes), past polls