Perl adding corresponding/respective values of array to variables - arrays

I have some scalar values in array
#array=(1,2,3,4,5);
We can directly assign these values to variables as
($a,$b,$c,$d,$e)=#array;
Is there some way so that I can add the corresponding values of #array numbers like
$x +=10;
($a,$b,$c,$d,$e) +=#array;
Sorry for asking such silly question ;)

Try using map
my #array=(1,2,3,4,5);
my ($a,$b,$c,$d,$e) = map { $_ + 10 } #array;

You can sum all elements of array using sum from List::Util:
use List::Util qw(sum);
my $sum = sum(#array);
UPDATE:
It seems that you want to add arrays element by element, then you can use pairwise from List::Moreutils:
use List::MoreUtils qw(pairwise);
my #array = qw(10 20 30);
my #incr = qw( 1 2 3);
pairwise { $a += $b } #array, #incr; # (11,22,33)

Related

Replicate the array number of times in Perl

I have array which contains 5 elements (1,2,3,4,5). I want to replicate this a number of times based on the value set in the scalar $no_of_replication, e.g. 3.
So that my final array would contain (1,2,3,4,5,1,2,3,4,5,1,2,3,4,5).
Here is what I have tried. It gives me scalar content instead of elements.
use strict;
use warnings;
use Data::Dumper;
my #array = (1,2,3,4,5);
print Dumper(\#array);
my $no_of_replication = 3;
my #new_array = #array * $no_of_replication;
print Dumper(\#new_array);
My array(#new_array) should be like (1,2,3,4,5,1,2,3,4,5,1,2,3,4,5).
The operator for that is x and you need to be careful with the array syntax:
#new_array = ( #array ) x $no_of_replication;
Found the solution here:
Multiplying strings and lists in perl via Archive.org

An elegant way of returning the index of the last non-zero element in Perl?

I find myself wanting to find the index of the last non-zero element in an array. So, given:
my #array = (0,0,5,9,0,0,0,7,0,3,0,0);
my $indexLastNonZero = insertElegantMethodHere(#array);
# expect $indexLastNonZero to be equal to 9;
I've done this:
for my $i (0 .. $#array) {
$indexLastNonZero = $i if $array[$i] != 0;
};
I works but somehow I can't help feel there must be a super elegant (smarter? nice? more efficient?) way of doing this in perl. I've looked into List::Utils but not found a nice way there and would like a non-core-module independent method.
Any thoughts?
Cheers
Use List::MoreUtils for such tasks:
use warnings;
use strict;
use List::MoreUtils;
my #array = (0,0,5,9,0,0,0,7,0,3,0,0);
print List::MoreUtils::lastidx { $_ } #array
Start at the end of the array and work backwards until you find a non-zero element:
my #array = (0,0,5,9,0,0,0,7,0,3,0,0);
my $i = $#array;
$i-- while $i >= 0 && $array[$i] == 0;
print "The last non-zero element is at index $i\n";
The $i >= 0 test is to guard against the edge case where all elements are zero. In that case the resulting value of $i is -1.
my #array = (0,0,5,9,0,0,0,7,0,3,0,0);
my ($indexLastNonZero) = grep $array[$_], reverse 0 .. $#array;
You could use List::Util, which is in core:
use strict;
use warnings;
use List::Util qw(first);
my #array = (0,0,5,9,0,0,0,7,0,3,0,0);
my $index = #array;
first { $index-- && $_ } reverse #array;
print "Last index that is non-zero: $index\n";
Destructive approach so take a copy of the array first:
my #array2 = #array;
while (!pop #array2) {} # Remove up to and including the last non-zero
print scalar #array2; # Size of remaining elements is index of last non-zero
sub last_true {
pop and return scalar #_ while #_;
undef;
}
my $index = last_true(#foo);

Check words and synonyms

I have an array with some words, and another array with words and synonyms. I'd like to create a third array when I find a matchin word between first and second array. I tried with grep but I'm not able to write the code in a proper way in order to get what I want.
The problem is that elements in array 1 can be found in array 2 at the beginning but also at the end or in the middle.
Maybe it's easier with an exemple:
#array1 = qw(chose, abstraction);
#array2 = (
"inspirer respirer",
"incapable",
"abstraction",
"abaxial",
"cause,chose,objet",
"ventral",
"chose,objet"
);
The result it should be
#array3 = ("abstraction", "cause,chose,objet", "chose,objet");
Is it right to use "grep"?
I'm not able to write a right syntax to solve the problem..
Thank you
You can construct a regular expression from the array1, then filter the array2 using it:
#!/usr/bin/perl
use warnings;
use strict;
my #array1 = qw(chose, abstraction);
my #array2 = (
"inspirer respirer",
"incapable",
"abstraction",
"abaxial",
"cause,chose,objet",
"ventral",
"chose,objet"
);
my $regex = join '|', map quotemeta $_, #array1; # quotemeta needed for special characters.
$regex = qr/$regex/;
my #array3 = grep /$regex/, #array2;
print "$_\n" for #array3;
I know you have an answer but here is a fun way I thought of.
So, I guess it is like an inverted index.
You take each set of synonyms and make them into an array. Then take each element of that array and put it into a hash as the keys with the value being a reference to the array.
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my #array1 = qw(chose abstraction);
my #array2 = ("inspirer respirer",
"incapable",
"abstraction",
"abaxial",
"cause,chose,objet",
"ventral",
"chose,objet"
);
my #array;
push #array, map { /,|\s/ ? [split(/,|\s/, $_)]:[$_] } #array2;
my %construct;
while(my $array_ref = shift(#array)){
for(#{ $array_ref }){
push #{ $construct{$_} }, $array_ref;
}
}
my #array3 = map { s/,//; (#{ $construct{$_} }) } #array1;
print join(', ', #{ $_ }), "\n" for (#array3);
EDIT:
Missed apart of the answer before, this one should be complete.

In Perl is it possible to transform an array using another array position by position?

I have an array of values which I'd like to transform using another array, like so
#raw_values = qw(10 20 30 40);
#adjustment_factors = qw(1 2 3 4);
#the expected value array
#expected_values = qw(10 40 90 160);
Is there a more perlish way to doing that then this?
for my $n (0..$#raw_values){
$expected_values[ $n ] = $raw_values[ $n ] * $adjustment_factors[ $n ]
}
The arrays always have the same number of elements, and I have a few thousand to process.
Use map:
#expected_values = map { $raw_values[$_] * $adjustment_factors[$_] } 0 .. $#raw_values;
Another option is to first assign the original values and then modify them:
#expected_values = #raw_values;
$x = 0;
$_ *= $adjustment_factors[$x++] for #expected_values;
Or, if you do not need #adjustment_factors anymore, you can empty it:
#expected_values = map { $_ * shift #adjustment_factors } #raw_values;
pairwise is the more idiomatic, CPAN solution.
use List::MoreUtils qw<pairwise>;
my #expected_values = pairwise { $a * $b } #raw_values, #adjustment_factors;
See List::MoreUtils

Perl - Split Array in to Smaller Evenly Distributed Arrays

How would I split a Perl array of arbitrary size in to a variable number of smaller arrays with the number of elements in each smaller array being distibuted as evenly possible? The original array must not be destroyed.
Off the top of my head:
use strict;
use warnings;
use Data::Dumper; # for debugging only
print Dumper(distribute(7, [1..30]));
# takes number+arrayref, returns ref to array of arrays
sub distribute {
my ($n, $array) = #_;
my #parts;
my $i = 0;
foreach my $elem (#$array) {
push #{ $parts[$i++ % $n] }, $elem;
};
return \#parts;
};
This guarantees that number of elements in #parts may only differ by one. There's anonther solution that would count the numbers beforehand and use splicing:
push #parts, [ #$array[$offset..$offset+$chunk] ];
$offset += chunk;
# alter $chunk if needed.
Here's a version using List::MoreUtils:
use strict;
use warnings;
use List::MoreUtils qw(part);
use Data::Dumper;
my #array = 1..9;
my $partitions = 3;
my $i = 0;
print Dumper part {$partitions * $i++ / #array} #array;
If you don't care what winds up in each array:
use strict;
use warnings;
use List::MoreUtils qw(part);
use Data::Dumper;
my $i = 0;
my $numParts = 2;
my #part = part { $i++ % $numParts } 1 .. 30;
print Dumper #part;
#Dallaylaen's answer doesn't quite work because you can't pass an array into a subroutine in Perl. Instead of passing in an array (or a list as Dallaylaen did in his example) you must pass in a reference to an array:
my #arrayIn = (1..30);
my #arrayOfArrays = distribute(7, \#arrayIn);
sub distribute {
my ($n, $array) = #_;
my #parts;
my $i = 0;
foreach my $elem (#$array) {
push #{ $parts[$i++ % $n] }, $elem;
};
return #parts;
};

Resources