Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

Add new data to array

by Anonymous Monk
on Mar 13, 2020 at 20:57 UTC ( [id://11114234]=perlquestion: print w/replies, xml ) Need Help??

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

Hi Monks!

I am trying to add new data to an array, but cant figure it out the best way, I am getting an error:

Not an ARRAY reference at code.pl

Here is a sample data and code, may be one of you can show me what the best solution.

Sample Data:
$VAR1 = { Ad1 => '20 SOUTH CENTRAL #B3', status => 'Property', City => 'NY', zCode => '0002', name => 'John D' }; $VAR1 = { Ad1 => '15 SOUTH CENTRAL #B4', status => 'Property', City => 'NY', zCode => '0002', name => 'John V' }; $VAR1 = { Ad1 => '100 main St.', status => 'houses', City => 'BO', zCode => '0007', name => 'Mary' };

Sample code:
#!/usr/bin/perl use warnings; use strict; use Data::Dumper; foreach my $row (@$data) { if ($row->{ 'status' } eq "houses") { my $name = $row->{ 'name' } || ''; my $ad1 = $row->{ 'Ad1' } || ''; my $town = $row->{ 'City' } || ''; my $zcode = $row->{ 'zCode' } || ''; push @{$data}, {new_name => $name, new_ad1 => $ad1, new_City => $ +town, new_z_code => $zcode}; } } print Dumper @$data;

Data results expected:
$VAR1 = { Ad1 => '20 SOUTH CENTRAL #B3', status => 'Property', City => 'NY', zCode => '0002', name => 'John D', new_Ad1 => '100 main St.', new_status => 'houses', new_City => 'BO', new_zCode => '0007', new_name => 'Mary }; $VAR1 = { Ad1 => '15 SOUTH CENTRAL #B4', status => 'Property', City => 'NY', zCode => '0002', name => 'John V', new_Ad1 => '100 main St.', new_status => 'houses', new_City => 'BO', new_zCode => '0007', new_name => 'Mary }; $VAR1 = { Ad1 => '100 main St.', status => 'houses', City => 'BO', zCode => '0007', name => 'Mary', new_Ad1 => '100 main St.', new_status => 'houses', new_City => 'BO', new_zCode => '0007', new_name => 'Mary };

Thanks for looking!

Replies are listed 'Best First'.
Re: Add new data to array
by AnomalousMonk (Archbishop) on Mar 13, 2020 at 23:27 UTC

    Your expected output is not consistent with your example input (which you don't show, but which we can make a good guess at) and the operations you show, but here's a guess at something you might find useful.

    c:\@Work\Perl\monks>perl -wMstrict -MData::Dumper -le "my $data = [ { Ad1 => '20 SOUTH CENTRAL #B3', status => 'Property', City => 'NY +', zCode => '0002', name => 'John D' }, { Ad1 => '15 SOUTH CENTRAL #B4', status => 'Property', City => 'NY +', zCode => '0002', name => 'John V' }, { Ad1 => '100 main St.', status => 'houses', City => 'BO +', zCode => '0007', name => 'Mary' }, ]; ;; foreach my $hr_row (@$data) { if ($hr_row->{ 'status' } eq 'houses') { my $name = $hr_row->{ 'name' } || ''; my $ad1 = $hr_row->{ 'Ad1' } || ''; my $town = $hr_row->{ 'City' } || ''; my $zcode = $hr_row->{ 'zCode' } || ''; ;; @{ $hr_row }{ qw(new_name new_ad1 new_City new_z_code) } = ( $name, $ad1, $town, $zcode ); } } ;; print Dumper $data; " $VAR1 = [ { 'status' => 'Property', 'name' => 'John D', 'Ad1' => '20 SOUTH CENTRAL #B3', 'City' => 'NY', 'zCode' => '0002' }, { 'status' => 'Property', 'name' => 'John V', 'Ad1' => '15 SOUTH CENTRAL #B4', 'City' => 'NY', 'zCode' => '0002' }, { 'new_City' => 'BO', 'status' => 'houses', 'new_ad1' => '100 main St.', 'name' => 'Mary', 'Ad1' => '100 main St.', 'City' => 'BO', 'new_z_code' => '0007', 'new_name' => 'Mary', 'zCode' => '0007' } ];
    Please see Short, Self-Contained, Correct Example, How do I post a question effectively? and How (Not) To Ask A Question (and maybe I know what I mean. Why don't you?).


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

      Its almost like that, I just need all the new data to be in all arrays as well:
      { 'status' => 'Property', 'name' => 'John D', 'Ad1' => '20 SOUTH CENTRAL #B3', 'City' => 'NY', 'zCode' => '0002', 'new_City' => 'BO', 'new_ad1' => '100 main St.', 'new_z_code' => '0007', 'new_name' => 'Mary', }, { 'status' => 'Property', 'name' => 'John V', 'Ad1' => '15 SOUTH CENTRAL #B4', 'City' => 'NY', 'zCode' => '0002', 'new_City' => 'BO', 'new_ad1' => '100 main St.', 'new_z_code' => '0007', 'new_name' => 'Mary' }, { 'new_City' => 'BO', 'status' => 'houses', 'new_ad1' => '100 main St.', 'name' => 'Mary', 'Ad1' => '100 main St.', 'City' => 'BO', 'new_z_code' => '0007', 'new_name' => 'Mary', 'zCode' => '0007' }

      Thanks!!!!
Re: Add new data to array
by jo37 (Deacon) on Mar 13, 2020 at 21:26 UTC

    This does not compile:

    Global symbol "$data" requires explicit package name at pm-11114234.pl + line 9. Global symbol "$data" requires explicit package name at pm-11114234.pl + line 18. Global symbol "$data" requires explicit package name at pm-11114234.pl + line 24. pm-11114234.pl had compilation errors.

    -jo

      I know, I added the data above and the sample program to show the issue.

        You have an issue with $data but hide it to us. That's my point.

        -jo

Re: Add new data to array
by swl (Parson) on Mar 13, 2020 at 22:26 UTC

    I'm guessing that you want to add the new values into the hashref that is $row, not to the arrayref that is $data?

    If so then you can use slice assignment (untested):

    my %new_row_data = (new_name => $name, new_ad1 => $ad1, new_City +=> $town, new_z_code => $zcode); @$row{keys %new_row_data} = values %new_row_data;

    You could also loop over the keys of %new_row_data and add each key/value pair in turn if that's easier to follow. The slice is more efficient, though, so better for very large data sets.

    my %new_row_data = (new_name => $name, new_ad1 => $ad1, new_City => +$town, new_z_code => $zcode); foreach my $key (keys %new_row_data) { $row->{$key} = $new_row_data{$key}; }
      I want to extract the values found in $row and add to all arrayrefs in $data.

        Assuming that the "Sample Data" in the OP was produced by a statement like
            print Dumper @$data;
        then there are no arrayrefs in $data; rather, $data is a reference to an array containing elements that are hash references.

        The
            foreach my $row (@$data) { ... }
        loop of the OPed code iterates over the elements of the array referenced by $data; these elements are hash references. The $row scalar is aliased in turn to each hash reference and thus becomes a hash reference.

        The
            if ($row->{ 'status' } eq "houses") { ... }
        conditional block within the for-loop of the OPed code suggests you want to extract certain values from each referenced hash for which  $row->{ 'status' } eq "houses" is true, and your statement here suggests you want to then add the most recently extracted set of values back into all of the hash references of the array. This doesn't seem to make any sense, but it can be done:

        c:\@Work\Perl\monks>perl -wMstrict -MData::Dumper -le "my $data = [ { Ad1 => '20 SOUTH CENTRAL #B3', status => 'Property', City => 'NY +', zCode => '0002', name => 'John D' }, { Ad1 => '15 SOUTH CENTRAL #B4', status => 'Property', City => 'NY +', zCode => '0002', name => 'John V' }, { Ad1 => '100 main St.', status => 'houses', City => 'BO +', zCode => '0007', name => 'Mary' }, ]; ;; my %last_houses; ;; foreach my $hr_row (@$data) { if ($hr_row->{ 'status' } eq 'houses') { @last_houses { qw(new_name new_ad1 new_City new_z_code) } = @{ $hr_row }{ qw(name Ad1 City zCode ) }; } } ;; foreach my $hr_row (@$data) { %$hr_row = (%$hr_row, %last_houses); } ;; print Dumper $data; " $VAR1 = [ { 'new_City' => 'BO', 'status' => 'Property', 'name' => 'John D', 'City' => 'NY', 'Ad1' => '20 SOUTH CENTRAL #B3', 'new_ad1' => '100 main St.', 'new_z_code' => '0007', 'zCode' => '0002', 'new_name' => 'Mary' }, { 'new_City' => 'BO', 'status' => 'Property', 'name' => 'John V', 'City' => 'NY', 'Ad1' => '15 SOUTH CENTRAL #B4', 'new_ad1' => '100 main St.', 'new_z_code' => '0007', 'zCode' => '0002', 'new_name' => 'Mary' }, { 'new_City' => 'BO', 'status' => 'houses', 'name' => 'Mary', 'City' => 'BO', 'Ad1' => '100 main St.', 'new_ad1' => '100 main St.', 'new_z_code' => '0007', 'zCode' => '0007', 'new_name' => 'Mary' } ];
        Again, please consider if this makes any sense.

        Update: Also, please consider what output you would want if your input were

        my $data = [ { Ad1 => '20 SOUTH CENTRAL #B3', status => 'Property', City => 'NY' +, zCode => '0002', name => 'John D' }, { Ad1 => '15 SOUTH CENTRAL #B4', status => 'Property', City => 'NY' +, zCode => '0002', name => 'John V' }, { Ad1 => '100 main St.', status => 'houses', City => 'BO' +, zCode => '0007', name => 'Mary' }, { Ad1 => '13 Terminal St.', status => 'houses', City => 'LA' +, zCode => '6664', name => 'Larry' }, ];


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

Re: Add new data to array
by BillKSmith (Monsignor) on Mar 14, 2020 at 13:50 UTC
    From your code, I can guess that $data is a reference to an array of hashes. You wish to add four new keys to each of these hashes. The values corresponding to these keys comes from one of these hashes. The source hash is the one with a status of 'houses'.
    use strict; use warnings; use Data::Dumper; my $data = [ { Ad1 => '20 SOUTH CENTRAL #B3', status => 'Property', City => 'NY', zCode => '0002', name => 'John D' }, { Ad1 => '15 SOUTH CENTRAL #B4', status => 'Property', City => 'NY', zCode => '0002', name => 'John V' }, { Ad1 => '100 main St.', status => 'houses', City => 'BO', zCode => '0007', name => 'Mary' }, ]; my @add_ins = grep { $_->{status} eq 'houses' } @$data; my $add_in = $add_ins[0]; foreach my $row (@$data) { $row->{new_name} = $add_in->{name} // ''; $row->{new_Ad1} = $add_in->{Ad1} // ''; $row->{new_City} = $add_in->{City} // ''; $row->{new_zCode} = $add_in->{zCode} // ''; } print Dumper($data);

    OUTPUT:

    $VAR1 = [ { 'name' => 'John D', 'new_zCode' => '0007', 'new_Ad1' => '100 main St.', 'Ad1' => '20 SOUTH CENTRAL #B3', 'zCode' => '0002', 'new_City' => 'BO', 'new_name' => 'Mary', 'status' => 'Property', 'City' => 'NY' }, { 'new_Ad1' => '100 main St.', 'Ad1' => '15 SOUTH CENTRAL #B4', 'name' => 'John V', 'new_zCode' => '0007', 'new_name' => 'Mary', 'new_City' => 'BO', 'status' => 'Property', 'City' => 'NY', 'zCode' => '0002' }, { 'new_Ad1' => '100 main St.', 'Ad1' => '100 main St.', 'name' => 'Mary', 'new_zCode' => '0007', 'new_City' => 'BO', 'new_name' => 'Mary', 'City' => 'BO', 'status' => 'houses', 'zCode' => '0007' } ];
    Bill

      It's possible to further simplify this (slightly) by removing the intermediate array variable:
          my ($add_in) = grep { $_->{status} eq 'houses' } @$data;
      (And I think it should be noted that the  // defined-or operator was added with Perl version 5.10.)


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

        Even better way:
        use List::Util qw(first); .. my $add_in = first { $_->{status} eq 'houses' } @$data;
        Bill
      Why this,

      my $add_in = $add_ins[0];

      couldn't be like this?
      my $add_in = (); my @$add_in = $add_ins[0];

      Thanks!

        WRT this code, because  $add_ins[0] is a hash reference (@add_ins is an array of hash references) and so  $add_in would become (by autovivification) a reference to an array holding a single element: a hash reference. The expression  $add_in->{name} would then have to become  $add_in->[0]{name} which would be possible, but a useless complication.

        Update 1: Normally, a statement like
            my @$add_in = $add_ins[0];
        would be written
            my @$add_in = ($add_ins[0]);
        using parentheses to make the RHS a proper list, but in the special case of single-element array assignment, Perl allows the parentheses to be dispensed with. In
            my $add_in = ();
        the parentheses have no effect; the statement is equivalent to
            my $add_in;

        Update 2: BillKSmith covers a point which I neglected to mention: the statements
            my $add_in = ();
            my @$add_in = $add_ins[0];
        are syntactically incorrect due to the use of the my declarator in the second statement. However, if this operator is removed, what's left is code that can be made to compile and to run without warnings and to work, albeit IMHO in an ugly, confusing and inefficient manner as discussed above.

        c:\@Work\Perl\monks>perl -wMstrict -MData::Dump -le "my @add_ins = ({ qw(foo bar) }, { qw(biz boz) }); ;; my $add_in = (); @$add_in = $add_ins[0]; dd $add_in; print $add_in->[0]{'foo'} " [{ foo => "bar" }] bar


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

        I do not understand what you mean. Your code is not valid Perl.
        >type tryit.pl use strict; use warnings; my $add_in = (); my @$add_in = $add_ins[0]; >perl tryit.pl "my" variable $add_in masks earlier declaration in same scope at tryit +.pl line 4 . Can't declare array dereference in "my" at tryit.pl line 4, near "$add +_in =" Global symbol "@add_ins" requires explicit package name (did you forge +t to decla re "my @add_ins"?) at tryit.pl line 4. Execution of tryit.pl aborted due to compilation errors.

        I defined the array @add_ins to force grep to run in list context. Execution of grep returnes a list (which contained only one element) and assigned it to @add_ins. The statement my $add_in = $add_ins[0]; assigns the value of that element to the scalar $add_in. Note that the value is a reference to the hash which contains the data which is to be added to every hash. AnomolousMonk accomplished the same thing by using the extra parenthesis to force list context and used list assignment to extract the single reference.

        Bill

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others about the Monastery: (2)
As of 2024-04-20 05:29 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found