Create vectors with different lengths in perl - perl

I have wrote the following program:
use strict;
use warnings;
use 5.010;
my $nodesNumber = 100 ;
my $communitiesNumber = 10;
my $prob_communities = 0.3;
for my $i (1 .. $nodesNumber){
for my $j (1 .. $communitiesNumber){
my $random_number=rand();
if ($prob_comunities > $random_number){
say "$i $j";
}
}
}
This program gives as output a list of two columns of integers as:
1 2
1 4
2 2
2 5
2 7
...
I would like to create a vector in which the first element in the left column is counted once and the right column elements represents the value of the vector's components. I would like the output to look like:
vector[0][0]= 1
vector[0][1]= 2
vector[0][2]= 4
vector[1][0]= 2
vector[1][1]= 2
vector[1][2]= 5
vector[1][3]= 7
Any help?

#!/usr/bin/env perl
# file: build_vector.pl
use strict;
use warnings;
my #vector; # the 2-d vector
my %mark; # mark the occurrence of the number in the first column
my $index = -1; # first dimensional index of the vector
while (<>) {
chomp;
my ($first, $second) = split /\s+/;
next if $second eq '';
if (not exists $mark{$first}) {
$mark{ $first } = ++$index;
push #{ $vector[$index] }, $first;
}
push #{ $vector[$index] }, $second;
}
# dump results
for my $i (0..$#vector) {
for my $j (0..$#{ $vector[$i] }) {
print "$vector[$i][$j] ";
}
print "\n";
}
This script will processing the output of your script and build the vector in #vector. If your script has filename generator.pl, you can call:
$ perl generator.pl | perl build_vector.pl
UPDATE:
use strict;
use warnings;
my $nodesNumber = 100 ;
my $communitiesNumber = 10;
my $prob_communities = 0.3;
my #vector; # the 2-d vector
my %mark; # mark the occurrence of the number in the first column
my $index = -1; # first dimensional index of the vector
for my $i (1 .. $nodesNumber){
for my $j (1 .. $communitiesNumber){
my $random_number=rand();
if ($prob_communities > $random_number){
if (not exists $mark{$i}) {
$mark{ $i } = ++$index;
push #{ $vector[$index] }, $i;
}
push #{ $vector[$index] }, $j;
}
}
}
# dump results
for my $i (0..$#vector) {
for my $j (0..$#{ $vector[$i] }) {
print "$vector[$i][$j] ";
}
print "\n";
}

#!/usr/bin/env perl
use 5.010;
use strict;
use warnings;
use Const::Fast;
use Math::Random::MT;
const my $MAX_RAND => 10;
my $rng = Math::Random::MT->new;
my #v = map {
my $l = $rng->irand;
[ map 1 + int($rng->rand($MAX_RAND)), 0 .. int($l) ];
} 1 .. 5;
use YAML;
print Dump \#v;

Related

Perl power of the adjacency matrix

Does anyone know how they would find the n-th power of the adjacency matrix?
Here is the matrix I am trying to write the code for
0 0 1 0
0 0 1 0
1 1 0 1
0 0 1 0
and the 2nd power adjacency matrix is:
1 1 0 1
1 1 0 1
0 0 3 0
1 1 0 1
I am not sure how I can calculate it with a perl code
I only have a code for reading in my file
sub matrix_read_file {
my ($filename) = #_;
my #matrix;
open (my $F, '<', $filename) or die "Could not open $filename: $!";
while (my $line =<$F> ) {
chomp $line;
next if $line =~ /^\s*$/; # skip blank lines
my #row = split /\s+/, $line;
push #matrix, \#row;
}
close $F;
print "$matrix[2][1]\n"; #test to see if individual elements print
print "$matrix[1][2]\n";
return \#matrix;
}
Here is an example:
use v5.22.0; # signatures requires perl >= 5.22
use feature qw(say);
use strict;
use warnings;
use experimental qw(signatures);
use Data::Dumper;
{
my $m = [[0,0,1,0],[0,0,1,0],[1,1,0,1],[0,0,1,0]];
my $m2 = matmul( $m, $m );
print Dumper($m2);
}
# Assume $m1 has size [pxq] and $m2 has size [qxr] :
# p = number of rows in $m1
# q = number of columns in $m1 == number of rows in $m2
# r = number of columns in $m2
# result = [pxq] * [qxr] => [p x r]
sub matmul( $m1, $m2 ) {
my $p = $#$m1;
my $q = $#{$m1->[0]};
my $r = $#{$m2->[0]};
my #res;
for my $i (0..$p) {
for my $j (0..$r) {
my $sum = 0;
for my $k (0..$q) {
$sum += $m1->[$i][$k] * $m2->[$k][$j];
}
$res[$i][$j] = $sum;
}
}
return \#res;
}
Or alternatively, using the PDL module:
use feature qw(say);
use strict;
use warnings;
use PDL;
my $m = pdl [[0,0,1,0],[0,0,1,0],[1,1,0,1],[0,0,1,0]];
my $m2 = $m x $m;
print $m2;

Sum the odd and even indices of an array separately - Perl

I have an array of 11 elements. Where I want to sum the odd elements including the first and last elements as one scalar and the evens as another.
This is my code I am trying to use map adding 2 to each index to achieve the result but I think I have got it wrong.
use strict;
use warnings;
use Data::Dumper;
print 'Enter the 11 digiet serial number: ';
chomp( my #barcode = //, <STDIN> );
my #sum1 = map { 2 + $_ } $barcode[1] .. $barcode[11];
my $sum1 = sum Dumper( \#sum1 );
# sum2 = l2 + l4 + l6 + r8 + r10;
printf "{$sum1}";
What is a good way to achieve this?
Sum of even/odd indicies (what you asked for, but not what you want[1]):
use List::Util qw( sum ); # Or: sub sum { my $acc; $acc += $_ for #_; $acc }
my $sum_of_even_idxs = sum grep { $_ % 2 == 0 } 0..$#nums;
my $sum_of_odd_idxs = sum grep { $_ % 2 == 1 } 0..$#nums;
Sum of even/odd values (what you also asked for, but not what you want[1]):
use List::Util qw( sum ); # Or: sub sum { my $acc; $acc += $_ for #_; $acc }
my $sum_of_even_vals = sum grep { $_ % 2 == 0 } #nums;
my $sum_of_odd_vals = sum grep { $_ % 2 == 1 } #nums;
Sum of values at even/odd indexes (what you appear to want):
use List::Util qw( sum ); # Or: sub sum { my $acc; $acc += $_ for #_; $acc }
my $sum_of_vals_at_even_idxs = sum #nums[ grep { $_ % 2 == 0 } 0..$#nums ];
my $sum_of_vals_at_odd_idxs = sum #nums[ grep { $_ % 2 == 1 } 0..$#nums ];
Given that you know how many elements you have, you could use the following:
use List::Util qw( sum ); # Or: sub sum { my $acc; $acc += $_ for #_; $acc }
my $sum_of_vals_at_even_idxs = sum #nums[0,2,4,6,8,10];
my $sum_of_vals_at_odd_idxs = sum #nums[1,3,5,7,9];
I included these in case someone needing these lands on this Q&A.
Add up values at odd and at even indices
perl -wE'#ary = 1..6;
for (0..$#ary) { $_ & 1 ? $odds += $ary[$_] : $evens += $ary[$_] };
say "odds: $odds, evens: $evens"
'
Note for tests: with even indices (0,2,4) we have (odd!) values (1,3,5), in this (1..6) example
You can use the fact that the ?: operator is assignable
print 'Enter the 11 digiet serial number: ';
chomp( my #barcode = //, <STDIN> );
my $odd = 0;
my $even = 0;
for (my $index = 0; $index < #barcode; $index++) {
($index % 2 ? $even : $odd) += $barcode[$index];
}
This works by indexing over #barcode and taking the mod 2 of the index, ie dividing the index by 2 and taking the remainder, and if the remainder is 1 adding that element of #barcode to $even otherwise to $odd.
That looks strange until you remember that arrays are 0 based so your first number of the barcode is stored in $barcode[0] which is an even index.
chomp( my #barcode = //, <STDIN> ); presumably was supposed to have a split before the //?
#barcode will have all the characters in the line read, including the newline. The chomp will change the final element from a newline to an empty string.
Better to chomp first so you just have your digits in the array:
chomp(my $barcode = <STDIN>);
my #barcode = split //, $barcode;
Another Perl, if the string is of length 11 and contains only digits
$ perl -le ' $_="12345678911"; s/(.)(.)|(.)$/$odd+=$1+$3;$even+=$2/ge; print "odd=$odd; even=$even" '
odd=26; even=21
$
with different input
$ perl -le ' $_="12121212121"; s/(.)(.)|(.)$/$odd+=$1+$3;$even+=$2/ge; print "odd=$odd; even=$even" '
odd=6; even=10
$

Perl compare individual elements of two arrays

I have two files with two columns each:
FILE1
A B
1 #
2 #
3 !
4 %
5 %
FILE 2
A B
3 #
4 !
2 &
1 %
5 ^
The Perl script must compare column A in both both files, and only if they are equal, column B of FIlE 2 must be printed
So far I have the following code but all I get is an infinite loop with # from column B
use strict;
use warnings;
use 5.010;
print "enter site:"."\n";
chomp(my $s = <>);
print "enter protein:"."\n";
chomp(my $p = <>);
open( FILE, "< $s" ) or die;
open( OUT, "> PSP.txt" ) or die;
open( FILE2, "< $p" ) or die;
my #firstcol;
my #secondcol;
my #thirdcol;
while ( <FILE> )
{
next if $. <2;
chomp;
my #cols = split;
push #firstcol, $cols[0];
push #secondcol, $cols[1]."\t"."\t".$cols[3]."\t"."\t"."\t"."N\/A"."\n";
}
my #firstcol2;
my #secondcol2;
my #thirdcol2;
while ( <FILE2> )
{
next if $. <2;
my #cols2 = split(/\t/, $_);
push #firstcol2, $cols2[0];
push #secondcol2, $cols2[4]."\n";
}
my $size = #firstcol;
my $size2 = #firstcol2;
for (my $i = 0; $i <= #firstcol ; $i++) {
for (my $j = 0; $j <= #firstcol2; $j++) {
if ( $firstcol[$i] eq $firstcol2[$j] )
{
print $secondcol2[$i];
}
}
}
my (#first, #second);
while(<first>){
chomp;
my $foo = split / /, $_;
push #first , $foo;
}
while(<second>){
chomp;
my $bar = split / / , $_;
push #second, $bar;
}
my %first = #first;
my %second = #second;
Build a hash of the first file as %first and second file as %second with first column as key and second column as value.
for(keys %first)
{
print $second{$_} if exists $second{$_}
}
I couldn't check it as I am on mobile. hope that gives you an idea.
I assume that column A is ordered and that you actually want to compare the first entry in File 1 to the first entry in File 2, and so on.
If that's true, you have nested loop that you don't need. Simplify your last while as such:
for my $i (0..$#firstcol) {
if ( $firstcol[$i] eq $firstcol2[$i] )
{
print $secondcol2[$i];
}
}
Also, if you're at all concerned about the files being of different length, then you can adjust the loop:
use List::Util qw(min);
for my $i (0..min($#firstcol, $#firstcol2)) {
Additional Note: You aren't chomping your data in the second file loop while ( <FILE2> ). That might introduce a bug later.
If your files are called file1.txt and file2.txt the next:
use Modern::Perl;
use Path::Class;
my $files;
#{$files->{$_}} = map { [split /\s+/] } grep { !/^\s*$/ } file("file$_.txt")->slurp for (1..2);
for my $line1 (#{$files->{1}}) {
my $line2 = shift #{$files->{2}};
say $line2->[1] if ($line1->[0] eq $line2->[0]);
}
prints:
B
^
equals in column1 only the lines A and 5
without the CPAN modules - produces the same result
use strict;
use warnings;
my $files;
#{$files->{$_}} = map { [split /\s+/] } grep { !/^\s*$/ } do { local(#ARGV)="file$_.txt";<> } for (1..2);
for my $line1 (#{$files->{1}}) {
my $line2 = shift #{$files->{2}};
print $line2->[1],"\n" if ($line1->[0] eq $line2->[0]);
}

How to produce range with step in Perl

In Bash, seq 5 5 20 produces 5 10 15 20.
In Perl, 1..5 produces 1 2 3 4 5; does it support step?
How do I produce a range with step in Perl?
perldoc -f map is one way:
use warnings;
use strict;
use Data::Dumper;
my #ns = map { 5 * $_ } 1 .. 4;
print Dumper(\#ns);
__END__
$VAR1 = [
5,
10,
15,
20
];
See also: perldoc perlop
The range operator in Perl doesn't support steps. You could use a for loop instead:
for (my $i = 5; $i <= 20; $i += 5) {
print "$i\n";
}
The List::Gen range function does this:
use strict;
use warnings;
use feature 'say';
use List::Gen;
my $range = range 5, 20, 5;
say for #$range; # 5
# 10
# 15
# 20
say while <$range>; # TIMT1WTDI
$range->say; # TAMT2WTDI, v.0.974
say $range->str; # TAMT3WTDI, v.0.974
my $by_fives = <5 .. 20 by 5>;
say while <$by_fives>; #TAMT4WTDI
<5 .. * by 5>->say( 4 ); #TAMT5WTDI
Not as good as toolic's answer:
use warnings;
use strict;
my #ns;
for my $n (1..4) {
push(#ns, $n*5);
}
I wrote Acme::Range::Module a while back as a gag module - hence the Acme:: namespace - but it does do what you want and has tests and is supported. Here's the example code:
use Acme::Globule qw( Range );
foreach (<10..1>) {
print "$_... ";
}
print "Lift-off!\n";
# put down that crack pipe...
sub my_keys(\%) {
my #hash = %{ $_[0] };
return #hash[ glob("0,2..$#hash") ];
}
sub my_values(\%) {
my #hash = %{ $_[0] };
return #hash[ glob("1,3..$#hash") ];
}
Here is an easy solution that utilizes map and the built-in range operator:
sub range {
my ($start, $end, $step) = #_;
$step ||= 1;
return map { $_ * $step } ($start / $step .. $end / $step);
}
Notice the key point here is the map {} block. We simply divide the end
by the given step (works for negative and positive) then map each value
to the multiple of the given step.
Like the map solution :)
Here it is used to look for files starting with even numbers in a range 116 to 648:
perl -e 'foreach (map { 2 * $_ } (116/2) .. (648/2)) { system("ls -l $_*"); } '
Perl is just wonderful for some jobs and making funny one-liners :)

How can I print undef values as zeros in Perl?

I'm building a count matrix in Perl using AoA: my #aoa = () then call $aoa[$i][$j]++ whenever I need to increment a specific cell. Since some cells are not incremented at all, they are left undef (these are equivalent to 0 counts).
I would like to print some lines from the matrix, but I get errors for undef cells (which I would simply like to print as zeros). what should I do?
Use defined with a conditional operator (?:).
#!/usr/bin/perl
use strict;
use warnings;
my #matrix;
for my $i (0 .. 3) {
for my $j (0 .. 3) {
if (rand > .5) {
$matrix[$i][$j]++;
}
}
}
for my $aref (#matrix) {
print join(", ", map { defined() ? $_ : 0 } #{$aref}[0 .. 3]), "\n"
}
If you are using Perl 5.10 or later, you can use the defined-or operator (//).
#!/usr/bin/perl
use 5.012;
use warnings;
my #matrix;
for my $i (0 .. 3) {
for my $j (0 .. 3) {
if (rand > .5) {
$matrix[$i][$j]++;
}
}
}
for my $aref (#matrix) {
print join(", ", map { $_ // 0 } #{$aref}[0 .. 3]), "\n"
}
Classically:
print defined $aoa[$i][$j] ? $aoa[$i][$j] : 0;
Modern Perl (5.10 or later):
print $aoa[$i][$j] // 0;
That is a lot more succinct and Perlish, it has to be said.
Alternatively, run through the matrix before printing, replacing undef with 0.
use strict;
use warnings;
my #aoa = ();
$aoa[1][1] = 1;
$aoa[0][2] = 1;
$aoa[2][1] = 1;
for my $i (0..2)
{
print join ",", map { $_ // 0 } #{$aoa[$i]}[0..2], "\n";
}
Just an example, please modify the code to your requirements.
use strict;
use warnings;
my #aoa;
$aoa[1][3]++;
foreach my $i (1 .. 3){
foreach my $j (1 .. 3){
defined $aoa[$i][$j] ? print $aoa[$i][$j] : print "0";
print "\t";
}
print "\n";
}