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!
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: <%-{-{-{-<
| [reply] [d/l] [select] |
|
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!!!! | [reply] [d/l] |
|
| [reply] [d/l] |
Re: Add new data to array
by jo37 (Deacon) on Mar 13, 2020 at 21:26 UTC
|
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
| [reply] [d/l] |
|
I know, I added the data above and the sample program to show the issue.
| [reply] |
|
| [reply] [d/l] |
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};
}
| [reply] [d/l] [select] |
|
I want to extract the values found in $row and add to all arrayrefs in $data.
| [reply] |
|
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: <%-{-{-{-<
| [reply] [d/l] [select] |
|
|
|
|
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'
}
];
| [reply] [d/l] [select] |
|
| [reply] [d/l] [select] |
|
use List::Util qw(first);
..
my $add_in = first { $_->{status} eq 'houses' } @$data;
| [reply] [d/l] |
|
|
Why this,
my $add_in = $add_ins[0];
couldn't be like this?
my $add_in = ();
my @$add_in = $add_ins[0];
Thanks! | [reply] [d/l] [select] |
|
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: <%-{-{-{-<
| [reply] [d/l] [select] |
|
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.
| [reply] [d/l] [select] |
|
|