Perl 2d Array Push - arrays

Why is there a difference in the creation of the following arrays #test1 and #test2?
#!/bin/perl -w
use Data::Dumper;
use warnings;
use strict;
my #test1 = [
['note', 1],
['note', 3]
];
print Dumper(#test1);
my #test2;
push(#test2, ['note', 1]);
push(#test2, ['note', 3]);
print Dumper(#test2);
Datadump for test1:
$VAR1 = [
[
'note',
1
],
[
'note',
3
]
];
Dumpt for test2:
$VAR1 = [
'note',
1
];
$VAR2 = [
'note',
3
];
Is there a possibility to create the same result of #test1 with iterative pushing to #test2?

Instead of:
my #test1 = [
['note', 1],
['note', 3]
];
You probably want:
my #test1 = (
['note', 1],
['note', 3]
);
The square brackets will create an anonymous array and will return a reference to the new array. So #test1 will contain a single scalar value which is a reference to an array.
Also when dumping a structure like an array, it is often clearer to prefix it with a backslash in order to pass a reference:
print Dumper(\#test2);
Which gives:
$VAR1 = [
[
'note',
1
],
[
'note',
3
]
];
Remember when you pass an array in a Perl function call, the array gets "flattened" into the argument list.

Related

How do I parse an array in perl that contains subarrays?

Let me preface by saying I'm a total novice at perl.
I need to modify rules on a mail system. I can access the rules as an array and I believe the array contains subarrays. I need to modify one particular element and preserve the rest. My problem is I'm confused as to what the array type really is and how to consistently access the elements.
There may be more than one set of rules, but I'm only interested in processing rules with a priority of '1', which is $Rule[0]. Within $Rule[3] I need to parse the addresses.
use strict;
use Data::Dumper qw(Dumper);
my $Rules=$cli->GetAccountMailRules($account);
print Dumper \#$Rules;
foreach my $Rule (#$Rules) {
if($Rule->[0]=~/1/) {
my $pri=$Rule->[0];
my $type=$Rule->[1];
my $auto=$Rule->[2];
my $actions=$Rule->[3];
my $action1;
my $auto1;
my $auto2;
my #newRule;
my $oldDest;
print "\n";
print "Priority:\n";
print Dumper \$pri;
print "\n";
print "Rule Type:\n";
print Dumper \$type;
print "\n";
print "Forward Auto?:\n";
print Dumper \$auto;
print "\n";
print "Actions:\n";
print Dumper \$actions;
print "\n";
foreach my $ax (#$actions) {
$action1=$ax->[0];
$oldDest=$ax->[1];
}
my #addresses=split /[;,]|\\e/, $oldDest;
my #dests = grep(/corp.com|corp1.com|corp2.com|corp3.com/, #addresses);
my $newDest = join(",", #dests);
if (#$auto) {
foreach my $au (#$auto) {
$auto1=$au->[0];
$auto2=$au->[1];
}
#newRule=(
[ $pri, $type,
[[$auto1,$auto2]],
[[$action1,$newDest]]
]
);
} else {
#newRule=(
[ $pri, $type,
[],
[[$action1,$newDest]]
]
);
}
}
}
}
Output thusly:
# perl removeRules.pl
$VAR1 = [
[
'1',
'#Redirect',
[
[
'Human Generated',
'---'
]
],
[
[
'Mirror to',
'test10#corp.com\\etest10#gmail.com\\etest10#corp1.com'
]
]
]
];
Priority:
$VAR1 = \'1';
Rule Type:
$VAR1 = \'#Redirect';
Forward Auto?:
$VAR1 = \[
[
'Human Generated',
'---'
]
];
Actions:
$VAR1 = \[
[
'Mirror to',
'test10#corp.com\\etest10#gmail.com\\etest10#corp1.com'
]
];
The problem I'm running into is there is an option within $actions to discard emails after forwarding, which introduces new elements (or subarray?) into $actions:
# perl removeRules.pl
$VAR1 = [
[
'1',
'#Redirect',
[
[
'Human Generated',
'---'
]
],
[
[
'Mirror to',
'test10#corp.com\\etest10#gmail.com\\etest10#corp1.com'
],
[ <---- Begin new elements
'Discard',
'---'
] <---- End new elements
]
]
];
Priority:
$VAR1 = \'1';
Rule Type:
$VAR1 = \'#Redirect';
Forward Auto?:
$VAR1 = \[
[
'Human Generated',
'---'
]
];
Actions:
$VAR1 = \[
[
'Mirror to',
'test10#corp.com\\etest10#gmail.com\\etest10#corp1.com'
],
[
'Discard',
'---'
]
];
I tried testing to see if they can be referenced as additional elements in $actions but it throws off the index.
my $action2;
my $action3;
print "Actions:\n";
print Dumper \$actions;
print "\n";
foreach my $ax (#$actions) {
$action1=$ax->[0];
$oldDest=$ax->[1];
$action2=$ax->[2];
$action3=$ax->[3];
}
print " action1 $action1\n";
print " oldDest $oldDest\n";
print " action2 $action2\n";
print " action3 $action3\n";
Output:
Actions:
$VAR1 = \[
[
'Mirror to',
'test10#corp.com\\etest10#gmail.com\\etest10#corp1.com'
],
[
'Discard',
'---'
]
];
action1 Discard
oldDest ---
Use of uninitialized value $action2 in concatenation (.) or string at removeRules.pl line 107, <GEN0> line 4.
action2
Use of uninitialized value $action3 in concatenation (.) or string at removeRules.pl line 108, <GEN0> line 4.
action3
Thank you in advance.
Using this:
[
[
'Mirror to',
'test10#corp.com\\etest10#gmail.com\\etest10#corp1.com'
],
[
'Discard',
'---'
]
]
This is a reference to an array (the outer [..]) that has two items. Each item is again a reference to an array.
First item (position 0 of outer array reference) is
[
'Mirror to',
'test10#corp.com\\etest10#gmail.com\\etest10#corp1.com'
],
and second (position 1) is:
[
'Discard',
'---'
]
If $ractions is this outer array, then the above two items are respectively under $ractions->[0] and $ractions->[1].
Since they are both an array reference again you can access their items using the same construct, or using a Perl property, you can remove the second array.
In short:
'Mirror to' can be accessed by $ractions->[0]->[0] or shorter $ractions->[0][0]
'test10#corp.com\etest10#gmail.com\etest10#corp1.com' can be accessed by $ractions->[0]->[1]
'Discard' can be accessed by $ractions->[1]->[0]
'---' can be accessed by $ractions->[1]->[1]
Be aware however that $VAR1 = \[ shows that you have a reference over a reference. So you will need an extra step of derefencing:
DB<1> use Data::Dumper;
DB<2> #a=(1,2)
DB<3> print Data::Dumper::Dumper(#a);
$VAR1 = 1;
$VAR2 = 2;
DB<4> print Data::Dumper::Dumper(\#a);
$VAR1 = [
1,
2
];
DB<5> print Data::Dumper::Dumper(\\#a);
$VAR1 = \[
1,
2
];
PS: do not use corp.com or anything like that when you need to obfuscate domain names. See guidance in RFC2606 or TL;DR: use example.com

Using join to concatenate array values

I have array values that is getting returned from SQL object.
my #keys = $db_obj->SelectAllArrayRef($sql);
print Dumper #keys;
gives
$VAR1 = [ [ '8853' ], [ '15141' ] ];
I need to create string from this array: 8853, 15141.
my $inVal = join(',', map { $_->[0] }, #$keys);
my $inVal;
foreach my $result (#$keys){
$inVal .= $result->[0];
}
my $inVal = join(',', #$keys);
Value i get is ARRAY(0x5265498),ARRAY(0x52654e0). I think its reference to the array. Any idea what am I missing here?
Don't pass arrays to Dumper; it leads to confusing output. $VAR1 is not a dump of #keys, it's a dump of $keys[0]. Instead, you should have done
print(Dumper(\#keys));
This would have given
$VAR1 = [ [ [ '8853' ], [ '15141' ] ] ];
The code you want is
join ',', map { $_->[0] }, #{ $keys[0] };
That said, it appears that ->SelectAllArrayRef returns a reference to the result, and so it should be called as follows:
my $keys = $db_obj->SelectAllArrayRef($sql);
For this,
print(Dumper($keys));
outputs
$VAR1 = [ [ '8853' ], [ '15141' ] ];
And you may use either of the methods you used in your question.
join ',', map { $_->[0] }, #$keys;
The first version should work for you:
my $arr = [ [ '8853' ], [ '15141' ] ];
my $values = join(',', map { $_->[0] } #$arr);
print $values . "\n";
8853,15141

access / print nth element of sub array, for every array

I have a multidimensional array:
#multarray = ( [ "one", "two", "three" ],
[ 4, 5, 6, ],
[ "alpha", "beta", "gamma" ]
);
I can access #multarray[0]
[
[0] [
[0] "one"
[1] "two"
[2] "three"
]
]
or even #multarray[0][0]
"one"
But how to I access say the 1st sub element of every sub array? something akin to multarray[*][0] so produce:
"one"
4
"alpha"
Thanks!
You can use map and dereference each array:
use warnings;
use strict;
use Data::Dumper;
my #multarray = (
[ "one", "two", "three" ],
[ 4, 5, 6, ],
[ "alpha", "beta", "gamma" ]
);
my #subs = map { $_->[0] } #multarray;
print Dumper(\#subs);
__END__
$VAR1 = [
'one',
4,
'alpha'
];
See also: perldsc
Using a for() loop, you can loop over the outer array, and use any of the inner elements. In this example, I've set $elem_num to 0, which is the first element. For each loop over the outer array, we take each element (which is an array reference), then, using the $elem_num variable, we print out the contents of the inner array's first element:
my $elem_num = 0;
for my $elem (#multarray){
print "$elem->[$elem_num]\n";
}

Perl Array Order

I'am new with perl and stucked with the following exercise.
I have a multi-array and want order its element to descending to the inside arrays sum's.
I want to make the order with Schwartzian transform.
This is my vector:
my #vectors = ( [1], [ 1, 2, 3 ], [4], [ 2, 2, 1 ] );
This is the expected vector:
#sorted_vectors = ( [1,2,3], [2,2,1], [4], [1] );
So far I am tried with these:
(1)
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my #vectors = ( [1], [ 1, 2, 3 ], [4], [ 2, 2, 1 ] );
my #sorted_vectors;
# #sorted_vectors = ( [1,2,3], [2,2,1], [4], [1] );
my %hash=();
for(my $i=0;$i< scalar #vectors;$i++){
$hash{$i}=#vectors[$i];
}
for my $key ( sort { $hash{$b}[1] <=> $hash{$a}[1] } keys %hash ) {
push(#sorted_vectors,[#{$hash{$key}}]);
}
print Dumper( \#sorted_vectors );
(2)
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my #vectors = ( [1], [ 1, 2, 3 ], [4], [ 2, 2, 1 ] );
my #sorted_vectors;
# #sorted_vectors = ( [1,2,3], [2,2,1], [4], [1] );
my #sorted = map { $_->[0] }
sort { $a->[1] cmp $b->[1] }
map { [$_, foo($_)] }
#vectors;
sub foo{
my $res = 0;
foreach my $x (#_) {
$res+= $x;
}
return $res;
}
print Dumper(\#sorted);
Your code works with few alterations,
my #sorted = map { $_->[0] }
# sort { $a->[1] cmp $b->[1] } # string sort, ascending order
sort { $b->[1] <=> $a->[1] } # numeric sort, descending order
# map { [$_, foo($_)] } # foo() expects list, not array reference
map { [$_, foo(#$_)] } # dereferencing $_ aref for foo()
#vectors;
or same thing but using sum() from core module List::Util
use List::Util 'sum';
my #vectors = ( [1], [ 1, 2, 3 ], [4], [ 2, 2, 1 ] );
my #sorted_vectors = map $_->[0],
sort { $b->[1] <=> $a->[1] }
map [ $_, sum(#$_) ],
#vectors;
use Data::Dumper; print Dumper \#sorted_vectors;
output
$VAR1 = [
[
1,
2,
3
],
[
2,
2,
1
],
[
4
],
[
1
]
];
This is simple with List::UtilsBy::rev_nsort_by and List::Util::sum:
my #vectors = ( [1], [ 1, 2, 3 ], [4], [ 2, 2, 1 ] );
my #sorted = rev_nsort_by { sum #$_ } #vectors;
This sorts the list of #vectors in reverse numerical order (i.e. largest number first) of the result of its control block. The control block here simply sums all the individual elements of each component.

initialise list with every element is a an associative array and last elment of the associative array is two d array in perl?

I'm trying to create a database .Each element in list contains details in the form of associative array and the last element of each of these associative array is a 2-d array,i need help initializing it ..
You need to say much more about what it is you are trying to do, but this may help: it initialises a Perl data structure in the way you have described. Note that there can be no "last" element of a hash (a better name than "associative array") as hashes are unordered. I have used the customers field of the data to hold the 2D array you talked about.
use strict;
use warnings;
my #list = (
{
id => 1,
name => 'cattle',
customers => [
[ 'World Bank', 'Space Marines', 'Undersea Exploration' ],
[ 1, 2, 3 ],
[ 0.0500, 0.6322, 0.9930 ],
],
},
{
id => 2,
name => 'arable',
customers => [
[ 'Jack Spratt', 'Molly Malone', 'The Whistler' ],
[ 4, 5, 6 ],
[ 0.0022, 0.1130, 0.6930 ],
],
},
{
id => 3,
name => 'seafood',
customers => [
[ 'Tai Chi School of Fishery', 'Latin Intermediary College', 'Ping Pong Gymnastics' ],
[ 7, 8, 9 ],
[ 0.0012, 0.8540, 0.9817 ],
],
},
);

Resources