Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

Pushing Arrays into Hash without nesting

by treeshark (Initiate)
on Feb 13, 2021 at 18:07 UTC ( #11128341=perlquestion: print w/replies, xml ) Need Help??

treeshark has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks,

I seek your wisdom. I've spent too much time banging my head and Googling this.
I believe it must be something to do with the difference between lists and arrays,
I can't work out how to push into my %hash{} in the same element from another hashes array without it breaking out into an array of arrays.

I'm sure that I'm doing something silly, but I can't see it and would really appreciate some of your wisdom.

The result I'm after is this:-
%hash - from main $VAR1 = 'foo'; $VAR2 = { 'bar' => [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ] };

Whereas I'm getting this:-
%hash - from main $VAR1 = 'foo'; $VAR2 = { 'bar' => [ 1, 2, 3, 4, 5, 6, 7, 8, 9, [ 10, 11, 12 ] ] };

This is my code

#!/usr/bin/perl; use strict; use warnings; use Data::Dumper; my %hash; my %source; my @array = (10 .. 12); $source{'data'} = \@array; print "\n".'%source'." - from main\n". Dumper %source; push (@ { $hash{"foo"}{"bar"} } , addSomeNumbers(1,3) ); print "\n".'%hash'." - from main\n". Dumper %hash; push (@ { $hash{"foo"}{"bar"} } , addSomeNumbers(4,6) ); print "\n".'%hash'." - from main\n". Dumper %hash; push (@ { $hash{"foo"}{"bar"} } , addSomeNumbersVia2ndSub(7,9) ); print "\n".'%hash'." - from main\n". Dumper %hash; push (@ { $hash{"foo"}{"bar"} } , addSomeNumbersFromSource("data") ); print "\n".'%hash'." - from main\n". Dumper %hash; sub addSomeNumbers{ my ($start, $end) = @_; my @array = ($start .. $end); print "\n".'@array'." - from addSomeNumbers\n". Dumper @array; return @array; } sub addSomeNumbersVia2ndSub{ my ($start, $end) = @_; my @array = addSomeNumbers($start, $end); print "\n".'@array'." - from addSomeNumbersVia2ndSub\n". Dumper @a +rray; return @array; } sub addSomeNumbersFromSource{ my ($data) = @_; my @array = $source{$data} ; return @array; }

Replies are listed 'Best First'.
Re: Pushing Arrays into Hash without nesting
by LanX (Cardinal) on Feb 13, 2021 at 18:28 UTC
    Hi treeshark, welcome to the monastery! :)

    my guess is that here in your last sub addSomeNumbersFromSource

    >

    my @array = $source{$data} ; return @array;

    you rather need to flatten the array-ref to a list before assigning it to another array.

    my @array = @{ $source{$data} } ; return @array;

    edit

    otherwise @array = ( [  ... the-source-data ... ] ) has just one array-ref. (aka a "nested array" in your words)

    whenever you have something like

    @array = $scalar

    that'll result into a one-element array.

    ... and $source{$data} is certainly a scalar, presumably holding an array-ref.

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery

      Perfect!
      Many thanks for your speedy reply
Re: Pushing Arrays into Hash without nesting
by tybalt89 (Prior) on Feb 13, 2021 at 19:28 UTC
    #!/usr/bin/perl use strict; use warnings; use Data::Dumper; my %hash; my %source; my @array = (10 .. 12); $source{'data'} = \@array; print "\n".'%source'." - from main\n". Dumper %source; push (@ { $hash{"foo"}{"bar"} } , addSomeNumbers(1,3) ); print "\n".'%hash'." - from main\n". Dumper %hash; push (@ { $hash{"foo"}{"bar"} } , addSomeNumbers(4,6) ); print "\n".'%hash'." - from main\n". Dumper %hash; push (@ { $hash{"foo"}{"bar"} } , addSomeNumbersVia2ndSub(7,9) ); print "\n".'%hash'." - from main\n". Dumper %hash; push (@ { $hash{"foo"}{"bar"} } , @{ (addSomeNumbersFromSource("data") +)[0] } ); print "\n".'%hash'." - from main\n". Dumper %hash; sub addSomeNumbers{ my ($start, $end) = @_; my @array = ($start .. $end); print "\n".'@array'." - from addSomeNumbers\n". Dumper @array; return @array; } sub addSomeNumbersVia2ndSub{ my ($start, $end) = @_; my @array = addSomeNumbers($start, $end); print "\n".'@array'." - from addSomeNumbersVia2ndSub\n". Dumper @a +rray; return @array; } sub addSomeNumbersFromSource{ my ($data) = @_; my @array = $source{$data} ; return @array; }
Re: Pushing Arrays into Hash without nesting
by 1nickt (Abbot) on Feb 13, 2021 at 20:37 UTC

    Hi,

    At the top of your script you have

    my @array = (10 .. 12); $source{'data'} = \@array;
    ... and then in the sub in question you have effectively
    $data = 'data'; # via arg my @array = $source{$data} ; return @array;

    First of all, why attempt to pass the array as a list? In general it's better to pass references around, like the one you stored in the hash. Just return the reference, and let the caller dereference and handle the list. You can dereference the result of the subroutine call, like this:

    push (@{ $hash{foo}{bar} }, @{ addSomeNumbersFromSource("data") });

    Hope this helps!


    The way forward always starts with a minimal test.
      push (@{ $hash{foo}{bar} }, @{ addSomeNumbersFromSource("data") });

      If addSomeNumbersFromSource() is not changed from the OPed code, then the
          return @array;
      statement will be evaluated in scalar context (dereferencing a scalar array reference) and will return the number of elements in @array.

      tybalt89 has it right for the given code:
         push (@ { $hash{"foo"}{"bar"} } , @{ (addSomeNumbersFromSource("data"))[0] } );

      Update:

      Just return the reference, and let the caller dereference and handle the list.
      Hmmm... On reading 1nickt's reply and re-reading the post to which I was replying, I must admit that that post urged a significant change to the function interface, for which the suggested expression invoking the function was perfectly appropriate. Paying attention to what's written can sometimes be useful. :)


      Give a man a fish:  <%-{-{-{-<

        Hm, yes, I did say "Just return the reference, and ...", in fact my whole point was that the subroutine should not return what the OP posted.


        The way forward always starts with a minimal test.
Re: Pushing Arrays into Hash without nesting
by BillKSmith (Prior) on Feb 14, 2021 at 20:18 UTC
    You do have a problem with 'list', but not in the way that you think. The first sentence of the DESCRIPTION section of the documentation for Data::Dumper is:
    Given a list of scalars or reference variables, writes out their contents in perl syntax.

    In your first call to Dumper, you specified '%hash', clearly a hash, not a scalar or a reference variable. In list context, perl converts this to a list of alternating keys and values. In your case, there is only one of each. They are dumped as '$VAR1' and '$VAR2'. By convention, you should specify a reference to your hash Dumper \%hash. There is a similar problem with all your other dumps. Correctly formed dumps would have helped you spot the problem ($source{$data} in addSomeNumbersFromSource contains a reference to an array, not an array). A simple fix is to dereference it before assigning to '@array'.

    #my @array = $source{$data} ; my @array = @{$source{$data}} ;
    Bill

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others taking refuge in the Monastery: (6)
As of 2021-05-15 18:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Perl 7 will be out ...





    Results (150 votes). Check out past polls.

    Notices?