I don't understand this Perl Syntax, has anyone got any idea? - arrays

I have got this part from a Perl plugin. I don't understand what it does. Is it an array of associative arrays? If so, then shouldn't it be started with #? Can anyone shed some light on this issue?
my $arguments =
[ { 'name' => "process_exp",
'desc' => "{BasePlugin.process_exp}",
'type' => "regexp",
'deft' => &get_default_process_exp(),
'reqd' => "no" },
{ 'name' => "assoc_images",
'desc' => "{MP4Plugin.assoc_images}",
'type' => "flag",
'deft' => "",
'reqd' => "no" },
{ 'name' => "applet_metadata",
'desc' => "{MP4Plugin.applet_metadata}",
'type' => "flag",
'deft' => "" },
{ 'name' => "metadata_fields",
'desc' => "{MP4Plugin.metadata_fields}",
'type' => "string",
'deft' => "Title,Artist,Genre" },
{ 'name' => "file_rename_method",
'desc' => "{BasePlugin.file_rename_method}",
'type' => "enum",
'deft' => &get_default_file_rename_method(), # by default rename imported files and assoc files using this encoding
'list' => $BasePlugin::file_rename_method_list,
'reqd' => "no"
} ];

As Bwmat said it's a reference to an Array of Hash references. Read
$ man perlref
or
$ man perlreftut # this is a bit more straightforward
for if you want to know more about references.
By the way in fiew words in Perl you can do:
#array = ( 1, 2 ); # declare an array
$array_reference = \#array; # take the reference to that array
$array_reference->[0] = 2; # overwrite 1st position of #array
$numbers = [ 3, 4 ]; # this is another valid array ref declaration. Note [ ] instead of ( )
the same thing happens with hashes.
By the way in fiew words in Perl you can do:
%hash = ( foo => 1, bar => 2 );
$hash_reference = \%hash;
$hash_reference->{foo} = 2;
$langs = { perl => 'cool', php => 'ugly' }; # this is another valid hash ref declaration. Note { } instead of ( )
And... yes, you can dereference these references.
%{ $hash_reference }
will be treated as it was a hash, so if you want to print the keys of $langs above, you can do:
print $_, "\n" foreach ( keys %{ $langs } );
To dereference an array ref use #{ } instead of %{ }. Even sub can be dereferenced.
sub foo
{
print "hello world\n";
}
my %hash = ( call => \&foo );
&{ $hash{call} }; # this allows you to call the sub foo

$arguments is an array reference (a reference/pointer to an array)
You initialize arrays with () and array references with []
my #array = ( 1, 2, 3 );
my $array_ref = [ 1, 2, 3 ];
You can create a reference with \
my $other_array_ref = \#array;
When you use an array reference you will then to dereference it when using:
for my $element ( #{$array_ref} )
or
print ${$array_ref}[0];
See man perlref
Back to your question: $arguments is a reference to an array of hash references (initialized with {})

Looks like a hash of hashes reference.
you may need to dereference like
%newhash = %{$arguments}
and print the data as
print $newhash{'name'}

Related

Perl: Can you use more than two arrays in the map function?

I've been learning Perl as of late, and ran into an interesting problem. How would I go about using two arrays in map like so?
use warnings;
use strict;
use Data::Dumper;
my $names->{name} = ['Bill', 'Smith'];
my $cars->{model} = ['Honda', 'Toyota'];
my $obj = {
'Students' => [
map {
'Name' => $_,
'Model' => $_
}, #{$names->{name}}, #{$cars->{model}}
]
};
print Dumper $obj;
This will print, it's producing two too many objects than I would like.
$VAR1 = {
'Students' => [
{
'Model' => 'Bill',
'Name' => 'Bill'
},
{
'Model' => 'Smith',
'Name' => 'Smith'
},
{
'Model' => 'Honda',
'Name' => 'Honda'
},
{
'Model' => 'Toyota',
'Name' => 'Toyota'
}
]
};
What I'd like to do is have map work in a way that it'll produce these results
$VAR1 = {
'Students' => [
{
'Model' => 'Honda',
'Name' => 'Bill'
},
{
'Model' => 'Toyota',
'Name' => 'Smith'
}
]
};
use warnings;
use strict;
use Data::Dumper;
my $names->{name} = [ qw(Bill Smith) ];
my $cars->{model} = [ qw(Honda Toyota) ];
my $obj = {
Students => [
map {
{ Name => $names->{name}[$_], Model => $cars->{model}[$_] }
}
0 .. $#{$names->{name}}
]
};
print Dumper $obj;
The body of the map uses both arrays so you only need to supply indices to it.
For this both arrayrefs must be of same length and items to be paired at same indices.
The syntax $#$arrayref is for the last index in the $arrayref, and since here we have to also dereference first there's an extra pair of {}.
What you have dereferences both arrayrefs, to build a single flat list for the map, producing
my $obj = {
'Students' => [
map {
'Name' => $_,
'Model' => $_
}, qw(Bill Smith Honda Toyota);
]
};
First, this makes no sense:
my $names->{name} = ['Bill', 'Smith'];
my $cars->{model} = ['Honda', 'Toyota'];
I'll use
my #names = ( 'Bill', 'Smith' );
my #models = ( 'Honda', 'Toyota' );
We could iterate over the indexes.
map { +{ Name => $names[$_], Model => $cars[$_] } }
0..$#names
Alternatively, we could enlist zip.
use List::Util qw( zip );
map { +{ Name => $_->[0], Model => $_->[1] } }
zip \#names, \#models
This is probably better written as a while loop:
my #names = qw( Bill Smith );
my #models = qw( Honda Toyota );
my #students;
push #students, { 'name' => shift #names, 'model' => shift #models } while #names;

How to send hash of hash of array items to csv

Hash of Hash of values were printing correctly to csv but hash of hash of array values are messing up my csv file. Please find my code below which is not working.
< use strict;
use warnings;
use Data::Dumper;
my %student_hash;
my $student_report = "StudentReport.csv";
%student_hash = (
'RollNummber1' => {
'studentname' => 'Boris',
'address' => ['Vietnam',
'local'
],
'DOB' => '5june2000'
},
'RollNummber2' => {
'studentname' => 'John',
'address' => [
'4th/floor',
'Culverdown/Street',
'WestHam',
'UK.',
],
'DOB' => '2feb2000'
},
'RollNummber3' => {
'studentname' => 'Karen',
'DOB' => '5march2000'
}
);
print "StudentHash:".Dumper(\%student_hash);
open(my $fh, '>', $student_report) or die("Couldn't open ile");
print $fh "DOB \t,ADDRESS \t,NAME \t\n";
foreach my $key(keys %student_hash){
foreach my $secondkeys (keys %{$student_hash{$key}}){
if($secondkeys =~ /DOB || studentname/) {
print $fh "$student_hash{$key}{$secondkeys} \t,"; }
if($secondkeys =~ /address/) {
print $fh Dumper $student_hash{$key}{$secondkeys} };
}
print $fh "\n";
}
close($fh);>
If I comment out printing the array part then the code works fine.Can someone please suggest how to print the array elements into csv either in one cell or in multiple cells.Thanks
Use Text::CSV - you can either use print if you've got an array reference to print. (It handles quoting for you).
Or you can use column_names to set the column ordering, and print_hr to output a hash ref in that order.
It looks like you're not worried about RollNumber so you can cheat and do:
foreach my $student ( values %student_hash ) {
}
To iterate. I'm unclear what you're trying to do with address. But a simple join would probably do the trick there. (either on linefeed or whitespace, depending on the desired output).
#!/usr/bin/env perl
use strict;
use warnings;
use Text::CSV;
my %student_hash = (
'RollNummber1' => {
'studentname' => 'Boris',
'address' => [ 'Vietnam', 'local' ],
'DOB' => '5june2000'
},
'RollNummber2' => {
'studentname' => 'John',
'address' => [ '4th/floor', 'Culverdown/Street', 'WestHam', 'UK.', ],
'DOB' => '2feb2000'
},
'RollNummber3' => {
'studentname' => 'Karen',
'DOB' => '5march2000'
}
);
my $csv = Text::CSV->new( { sep_char => ',', eol => "\n" } );
$csv->column_names( 'studentname', 'DOB', 'address' );
foreach my $student ( values %student_hash ) {
if ( defined $student -> {address} ) {
$student -> {address} = join (" ", #{$student->{address}});
}
$csv->print_hr( \*STDOUT, $student );
}

Perl interpreting following variable declaration

Hi all I have simple newbie question on perl. I am looking at someone's perl code and he has some variable declarations as follows:
my $OutputFiles=[];
$OutputFiles =
[
{ FID => 789133, TAGE => "BRWSGF_05K", nfiles => 1, Suffix => 'jpg' },
{ FID => 789134, TAGE => "BRWSGF_W05K", nfiles => 1, Suffix => 'jpg' },
{ FID => 789135, TAGE => "BRWSGF_E05K", nfiles => 1, Suffix => 'jpg' },
];
It seems to be some sort of array of hash but the variable declaration of $OutputFiles is not like that of an array so I am confused. Please let me know what is the variable $OutputFiles supposed to be and how can one manipulate such a variable.
Again I admit frankly that I am a rank Perl newbie.
[] creates an array reference, which is a scalar.
my $foo = [1, 2, 3];
Gives the same value of $foo as:
my #bar = (1, 2, 3);
my $foo = \#bar;
See perldoc perlref for more details.
$OutputFiles is an array reference, like Quentin's answer explained. You're also right that it is an array of hashes, but you can also think of it as an array of hash references. Here's how you can access the data:
#!/bin/perl
use strict;
use warnings;
my $OutputFiles=[];
$OutputFiles = [
{ FID => 789133, TAGE => "BRWSGF_05K", nfiles => 1, Suffix => 'jpg' },
{ FID => 789134, TAGE => "BRWSGF_W05K", nfiles => 1, Suffix => 'jpg' },
{ FID => 789135, TAGE => "BRWSGF_E05K", nfiles => 1, Suffix => 'jpg' },
];
my ($FID, $TAGE, $nfiles, $Suffix);
for my $hash_ref ( #$OutputFiles ) {
$FID = $hash_ref->{FID};
$TAGE = $hash_ref->{TAGE};
$nfiles = $hash_ref->{nfiles};
$Suffix = $hash_ref->{Suffix};
print "FID: $FID TAGE: $TAGE nfiles: $nfiles: Suffix: $Suffix\n";
}
As already mentioned by Quentin, it is array reference containing hashes, I am adding some small things how you can derefernce it & access the specific key from it as it contain hashes.
use strict;
use warnings;
use Data::Dumper;
my $OutputFiles=[];
$OutputFiles =
[
{ FID => 789133, TAGE => "BRWSGF_05K", nfiles => 1, Suffix => 'jpg' },
{ FID => 789134, TAGE => "BRWSGF_W05K", nfiles => 1, Suffix => 'jpg' },
{ FID => 789135, TAGE => "BRWSGF_E05K", nfiles => 1, Suffix => 'jpg' },
];
my #output = #{$OutputFiles}; #dereference the array ref
print Dumper(#output );
print Dumper(#{$OutputFiles}[0]->{FID}); # accessing the specific key

Perl- Iterating through an array of hashes with square brackets

I have a hash whose keys is a string and key is array(the complication is that the array is defined in the square bracket), So my hash is like this..
model = {
'add' => [
{'name' => 'abc1', 'value' => 'def' },
{'name' => 'abc2', value => 'ghi'}
],
'remove' => [
{'name' => 'abc1', 'value' => 'def' },
{'name' => 'abc2', value => 'ghi'}
]
};
So what I am trying to achive is that when I try to iterate through the hashes of array
model->{add} as
print $_->{name} foreach(model->{add})
it doesnt work.
I guess this is because the array is in [] instead of ().
Considering the input cannot be changed. please let me know how to get through this...
$model = { 'add' => [ {'name' => 'abc1', 'value' => 'def' },
{'name' => 'abc2', 'value' => 'ghi'} ],
'remove' => [ {'name' => 'abc1', 'value' => 'def' },
{'name' => 'abc2', 'value' => 'ghi'} ] };
print $_->{name} foreach( #{ $model->{add} } );
You have a 3-level nested structure: A HashRef containing ArrayRefs containing HashRefs.
my $model = {
'add' => [
{
'name' => 'abc1',
'value' => 'def'
}, {
'name' => 'abc2',
value => 'ghi'
}
],
'remove' => [
{
'name' => 'abc1',
'value' => 'def'
}, {
'name' => 'abc2',
value => 'ghi'
}
]
};
To access those nested arrays and hashes, you need to dereference them, by adding % or # in front of it, depending on whether it is a hash or array.
my $arrayref = $model->{add};
foreach my $hashref (#$arrayref) {
print $hashref->{name}, "\n";
}
The statement:
print $_->{name} foreach(model->{add})
Does not work because model is a bareword, not a variable. If you have these two pragmas in your code:
use strict;
use warnings;
You will not be able to make mistakes like this. warnings will tell you:
Unquoted string "model" may clash with future reserved word at ...
Name "main::model" used only once: possible typo at ...
Use of uninitialized value in print at ...
And strict will tell you:
Can't use bareword ("model") as a HASH ref while "strict refs" in use at ...
However, if you do not have those two pragmas enabled, Perl will happily print the empty string and be silent about the whole thing. Which makes the mistake rather hard to detect.
The correct way to handle this is to grab the correct scalar value from the hash, and dereference it using the correct sigil. If you look at the key 'add':
'add' => [
You'll see that it has an array reference stored in it, which means the sigil to use is #. You'll need support curly braces to disambiguate the references. Also, you have to refer to your variable as $model.
print $_->{name} for #{ $model->{add} };
Which is the same as
my $adds = $model->{add};
print $_->{name} for #$adds;
First and foremost use use strict; use warnings;
The scalar model should be written as
my $model = { 'add' => [ {'name' => 'abc1', 'value' => 'def' }, {'name' => 'abc2', value => 'ghi'} ], 'remove' => [ {'name' => 'abc1', 'value' => 'def' }, {'name' => 'abc2', value => 'ghi'} ] };
and
print $_->{name} foreach( ( #{ $model->{ add } } ) );

Find the size of an array of hash in Perl

How do you get the size of the following array of hashes?
I thought this would do it, but it did not work...
print Dumper scalar $item->{'detail'};
$VAR1 = [
{ 'content' => undef, 'name' => 'entree', 'url_name' => 'entree' },
{ 'content' => undef, 'name' => 'dessert', 'url_name' => 'desert' },
{ 'content' => undef, 'name' => 'drink', 'url_name' => 'drink' }
];
Or how can I print all the url_name (entree, desert, drink) in the array of hashes without knowing the size?
You have an array reference. To get the size of the referenced array, first dereference the reference:
print scalar #{$item->{'detail'}};
And to list the URLs:
my $v = [
{ 'content' => undef, 'name' => 'entree', 'url_name' => 'entree' },
{ 'content' => undef, 'name' => 'dessert', 'url_name' => 'desert' },
{ 'content' => undef, 'name' => 'drink', 'url_name' => 'drink' }
]; # or $v = $item->{'detail'};
foreach my $h (#$v) {
print $h->{url_name}, "\n";
}
I'm not sure why you think you need the array size in order to print the url_name values. Nonetheless, here's how it works.
use strict;
use warnings;
use Data::Dumper;
my $v = [ # note that this is a scalar value
{ 'content' => undef, 'name' => 'entree', 'url_name' => 'entree' },
{ 'content' => undef, 'name' => 'dessert', 'url_name' => 'desert' },
{ 'content' => undef, 'name' => 'drink', 'url_name' => 'drink' }
];
my $item = { detail => $v }; # recreate your structure $item->{detail}
my $size = #$v; # this is how its done with $v
my $size2 = #{ $item->{detail} }; # and with your original structure
my #x = map $_->{url_name}, #$v; # extract url_name values
print Dumper \#x;
As you see, $item->{detail} and $v are identical. When you feed this scalar value directly (through the scalar function, which does nothing in this case) to Dumper, you get the printed value seen in $v above. All that scalar does is change the context used with print and enforce a scalar context rather than list context. We can do the same thing by using scalar assignment ($size and $size2).
When using the original structure, you need to use the #{ } brackets to clarify for perl that what is inside them is an array ref.
As you see, extracting the values is easily done with a map statement. It acts as a loop, iterating over all the values in #$v (or #{ $item->{detail} }), returning for each value the statement $_->{url_name}.

Resources