perl: sprintf for element in list - perl

I've been really confused about this, I'm trying to create a big matrix of numbers and I want to use sprintf with perl to have a nicer output. I'm trying to use sprintf like so
my $x = 0;
my $y = 0;
for ($x=1; $x<=$steps; $y++) { # loop through lines
for ($y=0; $y<=$distances; $y++) {
my $format = sprintf ("%s",$matrix[$x][$y]);
but this is really doing my head in, as I am looping through all the values of $x and $y and getting their combinations. So I am not sure if I'm meant to use more formatting arguments like so
my $format = sprintf ("%s%s%s",$matrix[$x][$y]);
(of course this is giving me compilation errors as it's not right)
But when I only use one argument, I can't put spaces in between my columns :/ Can somebody explain what's happening? I really don't understand what I'm meant to do to get the formatting nice. I'm looking to just align the columns and have a couple of whitespaces between them. Thank you all so much.

I would be thinking in terms of using map, as a way to display every element:
#!/usr/bin/env perl
use strict;
use warnings;
my #matrix = ( [1,2,3,4],
[5,6,7,8],
[9,10,11,12], );
print join ("\n", map { join ( "\t", #$_ ) } #matrix );
This is formatting on tab-stops, rather than fixed width columns, and outputs:
1 2 3 4
5 6 7 8
9 10 11 12
If you particularly wanted sprintf though:
foreach my $row ( #matrix ) {
print map { sprintf("%5s", $_) } #$row,"\n";
}
(5 columns wide).
In each of these, I'm working on whole rows - that only really applies though, if I'm right about the assumptions I've made about which elements you're displaying.
At a very basic level - your code could work as:
#!/usr/bin/env perl
use strict;
use warnings;
my #matrix = ( [ 1, 2, 3, 4 ],
[ 5, 6, 7, 8 ],
[ 9, 10, 11, 12 ], );
my $steps = 2;
my $distances = 3;
for ( my $x = 1; $x <= $steps; $x++ ) { # loop through lines
for ( my $y = 0; $y <= $distances; $y++ ) {
printf( "%5s", $matrix[$x][$y] );
}
print "\n";
}
Although note - that will only work with equal numbers of columns. You could, however, do something like:
#!/usr/bin/env perl
use strict;
use warnings;
my #matrix = ( [ 1, 2, ],
[ 3, 4, 5, ],
[ 6, 7, 8, 9, 10, 11, 12 ], );
my $steps = 2;
my $distances = 3;
for ( my $x = 1; $x <= $steps; $x++ ) { # loop through lines
for ( my $y = 0; $y <= $distances; $y++ ) {
printf( "%5s", $matrix[$x][$y] // '' );
}
print "\n";
}
Which omits the first row (because you set $x to 1), and iterates up to 4 columns:
3 4 5
6 7 8 9
This omits the extra values on the last line, and uses // to test if the cell is empty or not.

for my $row (#matrix) {
my $format = join(' ', ('%5.2f') x #$row)."\n";
printf($format, #$row);
}
If all rows have the same number of columns, you could calculate the format once.
if (#matrix) {
my $format = join(' ', ('%5.2f') x #{$matrix[0]})."\n";
for my $row (#matrix) {
printf($format, #$row);
}
}
If the size of the columns isn't unknown in advance, you'll need to need to perform the following in order:
Format the cells (if needed),
Find the length of the largest cell of each column, then
Print out the matrix with padding.
The following assumes every row of the matrix is the same length.
use List::Util qw( max );
if (#matrix) {
for my $row (#matrix) {
$_ = sprinf('%.2f', $_) for #$row;
}
my $num_cols = #{$matrix[0]};
my #col_sizes = (0) x $num_cols;
for my $row (#matrix) {
$col_sizes[$x] = max(0, $col_sizes[$x], $row->[$x]);
}
my $format = join(' ', map { "%$_s" } #col_sizes)."\n";
for my $row (#matrix) {
printf($format, #$row);
}
}

Related

Perl: Create a binary number and convert it into hex

I want to create a binary number from the given user input.
Input - Array of number
Output - Binary number
A binary number should be created such that it has one on all the places which has been given as input.
In the given case input is 1, 3, and 7 so my binary no should be 1000101, so it has 1's on 1, 3 and 7 places from left.
#x = [ 1, 3, 7 ];
$z = 0;
for( $i = 0; $i < 10; $i++ ){
foreach $elem ( #x ){
if( $elem == $i ){
join( "", $z, 1 );
}
else{
join( "", $z, 0 );
}
}
}
print "Value of z: $z";
After execution, I am getting the value of z as 0.
I need to convert this binary to hexadecimal.
Is there some function which converts binary to hexadecimal?
[ ] creates an array and returns a reference to that array, so you are assigning a single scalar to (poorly named) #x.
You are also misusing join. Always use use strict; use warnings qw( all );! It would have caught this error.
Fixed:
my #bits = ( 1, 3, 7 );
my $num = 0;
$num |= 1 << $_ for #bits;
# 76543210
printf("0b%b\n", $num); # 0b10001010
printf("0x%X\n", $num); # 0x8A
It seems that you want 0b1000101, so we need to correct the indexes.
my #bits_plus_1 = ( 1, 3, 7 );
my $num = 0;
$num |= 1 << ( $_ - 1 ) for #bits_plus_1;
# 6543210
printf("0b%b\n", $num); # 0b1000101
printf("0x%X\n", $num); # 0x45
A few problems:
#x = [ 1, 3, 7 ]; is not an array of three integers. It's an array containing a single array reference. What you want is round brackets, not square brackets: #x = ( 1, 3, 7 );
The string returned by join is not assigned to $z
But even then your code is buggy:
it appends a bit at the end of $z, not the beginning
there's a trailing zero that has no business being there.

Please explain perl statement

I am reading Intermediate Perl book and in Chapt10 there is this code. I added few print statements but core logic is untouched.
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my #input = qw(Gilligan Skipper Professor Ginger Mary Ann);
my #sorted_positions = sort { $input[$a] cmp $input[$b] } 0 .. $#input;
print Dumper( \#sorted_positions );
my #ranks;
#ranks[#sorted_positions] = ( 1 .. #sorted_positions );
print Dumper( \#ranks );
foreach ( 0 .. $#ranks ) {
print "$input[$_] sorts into position $ranks[$_]\n";
}
When i check the Dumper output then for #sorted_positions array it is printing
$VAR1 = [
5,
0,
3,
4,
2,
1
];
which make sense to me but for #ranks array it is printing
$VAR1 = [
2,
6,
5,
3,
4,
1
];
I am unable to understand what this line is doing.
#ranks[#sorted_positions] = ( 1 .. #sorted_positions );
I am able understand what output means in reference to the program but not able to understand how that output is coming i.e. what exactly is perl doing inside that statement.
The line:
#ranks[#sorted_positions] = ( 1 .. #sorted_positions );
is equivalent to:
#ranks[5,0,3,4,2,1] = (1,2,3,4,5,6);
which is equivalent to:
$ranks[5] = 1;
$ranks[0] = 2;
$ranks[3] = 3;
$ranks[4] = 4;
$ranks[2] = 5;
$ranks[1] = 6;
The example is using slices which are documented in the perldata man page.
Let suppose you want to assign string 'x' into the first position of an array, 'y' into the second position and 'z' into the third position. Instead of doing three assignments, you can do them at the same time;
#array[0,1,2] = ("x", "y", "z");
You don't have to do these in order;
#array[2,0,1] = ("z", "x", "y"); # same result
The right-hand side of the line in question produces a list of numbers starting with 1 and finishing at the integer value returned by the expression #sorted_positions (which is 6 as there are 6 things in #sorted_positions) - ie its identical to;
(1,2,3,4,5,6)
So, the whole statement is identical to:
#ranks[5,0,3,4,2] = (1,2,3,4,5,6) ;
So, if we take just one iteration of this:
foreach ( 0 .. $#ranks ) {
print "$input[$_] sorts into position $ranks[$_]\n";
}
we get;
print "$input[0] sorts into position $ranks[0]\n"
# ie: Gilligan sorts into position 2
Hope that helps.

Performing a function on each combination of variables in two arrays

I am trying to take one set of data and subtract each value in that data by another set of data.
For example:
Data set one (1, 2, 3)
Data set two (1, 2, 3, 4, 5)
So I should get something like (1 - (1 .. 5)) then (2 - (1..5)) and so on.
I currently have:
#!/usr/bin/perl
use strict;
use warnings;
my $inputfile = $ARGV[0];
open( INPUTFILE, "<", $inputfile ) or die $!;
my #array = <INPUTFILE>;
my $protein = 'PROT';
my $chain = 'P';
my $protein_coords;
for ( my $line = 0; $line <= $#array; ++$line ) {
if ( $array[$line] =~ m/\s+$protein\s+/ ) {
chomp $array[$line];
my #splitline = ( split /\s+/, $array[$line] );
my %coordinates = (
x => $splitline[5],
y => $splitline[6],
z => $splitline[7],
);
push #{ $protein_coords->[0] }, \%coordinates;
}
}
print "$protein_coords->[0]->[0]->{'z'} \n";
my $lipid1 = 'MEM1';
my $lipid2 = 'MEM2';
my $lipid_coords;
for ( my $line = 0; $line <= $#array; ++$line ) {
if ( $array[$line] =~ m/\s+$lipid1\s+/ || $array[$line] =~ m/\s+$lipid2\s+/ ) {
chomp $array[$line];
my #splitline = ( split /\s+/, $array[$line] );
my %coordinates = (
x => $splitline[5],
y => $splitline[6],
z => $splitline[7],
);
push #{ $lipid_coords->[1] }, \%coordinates;
}
}
print "$lipid_coords->[1]->[0]->{'z'} \n";
I am trying to take every value in $protein_coords->[0]->[$ticker]->{'z'} minus each value in $lipid_coords->[1]->[$ticker]->{'z'}.
My overall objective is to find (z2-z1)^2 in the equation d = sqrt((x2-x1)^2+(y2-y1)^2-(z2-z1)^2). I think that if I can do this once then I can do it for X and Y also. Technically I am trying to find the distance between every atom in a PDB file against every lipid atom in the same PDB and print the ResID for distance less than 5A.
To iterate on all combinations of two arrays, just embed two for loops:
use strict;
use warnings;
my #dataone = (1, 2, 3);
my #datatwo = (1, 2, 3, 4, 5);
for my $one (#dataone) {
for my $two (#datatwo) {
print "$one - $two\n";
}
}
Outputs:
1 - 1
1 - 2
1 - 3
1 - 4
1 - 5
2 - 1
2 - 2
2 - 3
2 - 4
2 - 5
3 - 1
3 - 2
3 - 3
3 - 4
3 - 5
This will give you the result of subtracting each element of set 2 from each element of set 1 in what I believe is the manner you were asking.
#!/usr/bin/perl
use strict;
use warnings;
my #set1 = (1, 2, 3);
my #set2 = (1, 2, 3, 4, 5);
my #set3 = ();
for my $val (#set1) {
push #set3, map { $val - $_ } #set2;
}
local $" = ', ';
print "#set3\n";
system 'pause';
The result will be an array containing (1 - (1..5), 2 - (1..5), 3 - (1..5)).
Contents of #set3 after script runs:
0, -1, -2, -3, -4, 1, 0, -1, -2, -3, 2, 1, 0, -1, -2
All the other protein and lipid stuff is way over my head, but I hope this at least helps a little. You should now have an array containing the subtracted elements that you can work with to get the rest of your results!
Edit:
Can replace the loop with this one liner :)
my #set3 = map { my $v = $_; map { $v - $_ } #set2 } #set1;
map is a pretty nifty function!
The easiest way to do this is to do your calculations while you're going through file two:
for (my $line = 0; $line <= $#array; ++$line) {
if (($array[$line] =~ m/\s+$lipid1\s+/) | ($array[$line] =~ m/\s+$lipid2\s+/)) {
chomp $array[$line];
my #splitline = (split /\s+/, $array[$line]);
my %coordinates = (x => $splitline[5],
y => $splitline[6],
z => $splitline[7],
);
push #{$lipid_coords->[1]}, \%coordinates;
# go through each of the sets of protein coors in your array...
for my $p (#{$protein_coords->[0]}) {
# you can store this value however you want...
my $difference = $protein_coords->[0][$p]{z} - $coordinates{z};
}
}
}
If I were you, I would use some form of unique identifier to allow me to access the data on each combination -- e.g. build a hash of the form $difference->{<protein_id>}{<lipid_id>} = <difference>.

perl: function that gives nonzero integers between 1 and $input

Im looking for (how to make?) a function (module?) that for
my $scalar = 16;
return function ($scalar);
gives
#return = ( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 );
That is, gives the non-zero integers between 1 and $scalar.
It's ok to assume $scalar is a big number, but im not particularly searching for a super optimal solution.
The Range Operator .. returns a list which matches exactly what you want.
To create a list from 1 to $x, the syntax is just 1 .. $x
To assign that to an array variable, #array = 1 .. $x;
[1..16]
creates an array reference
1..16 creates a list.
Try this source
use Data::Dumper;
$c = [1..16];
#d = 1..16;
print Dumper $c;
print Dumper \#d;
sub getvalue {
my #array1 = 1..$_[0];
return (#array1);
}
else
sub getvalue {
return ( 1..$_[0]);
}
refer this too know more about range operator
http://www.perlmonks.org/?node_id=377450
What happens when you want all integers between 1 and 1_000_000_000? You wouldn't want to create an array that big even if your computer has enough memory.
#!/usr/bin/env perl
use strict;
use warnings;
sub make_lazy_increasing_sequence {
my ($current, $end) = map int, #_;
return sub {
return if $current > $end;
return $current++;
}
}
my $from_1_to_5 = make_lazy_increasing_sequence(1, 5);
my #others;
while (defined(my $i = $from_1_to_5->())) {
push #others, make_lazy_increasing_sequence($i, 10_000);
}
for (1 .. 10) { # perl makes sure this range is lazy
print join(',', map $_->(), #others), "\n";
}
print $others[-1]->(), "\n";
Output:
1,2,3,4,5
2,3,4,5,6
3,4,5,6,7
4,5,6,7,8
5,6,7,8,9
6,7,8,9,10
7,8,9,10,11
8,9,10,11,12
9,10,11,12,13
10,11,12,13,14
15

Is there an elegant zip to interleave two lists in Perl 5?

I recently "needed" a zip function in Perl 5 (while I was thinking about How do I calculate relative time?), i.e. a function that takes two lists and "zips" them together to one list, interleaving the elements.
(Pseudo)example:
#a=(1, 2, 3);
#b=('apple', 'orange', 'grape');
zip #a, #b; # (1, 'apple', 2, 'orange', 3, 'grape');
Haskell has zip in the Prelude and Perl 6 has a zip operator built in, but how do you do it in an elegant way in Perl 5?
Assuming you have exactly two lists and they are exactly the same length, here is a solution originally by merlyn (Randal Schwartz), who called it perversely perlish:
sub zip2 {
my $p = #_ / 2;
return #_[ map { $_, $_ + $p } 0 .. $p - 1 ];
}
What happens here is that for a 10-element list, first, we find the pivot point in the middle, in this case 5, and save it in $p. Then we make a list of indices up to that point, in this case 0 1 2 3 4. Next we use map to pair each index with another index that’s at the same distance from the pivot point as the first index is from the start, giving us (in this case) 0 5 1 6 2 7 3 8 4 9. Then we take a slice from #_ using that as the list of indices. This means that if 'a', 'b', 'c', 1, 2, 3 is passed to zip2, it will return that list rearranged into 'a', 1, 'b', 2, 'c', 3.
This can be written in a single expression along ysth’s lines like so:
sub zip2 { #_[map { $_, $_ + #_/2 } 0..(#_/2 - 1)] }
Whether you’d want to use either variation depends on whether you can see yourself remembering how they work, but for me, it was a mind expander.
The List::MoreUtils module has a zip/mesh function that should do the trick:
use List::MoreUtils qw(zip);
my #numbers = (1, 2, 3);
my #fruit = ('apple', 'orange', 'grape');
my #zipped = zip #numbers, #fruit;
Here is the source of the mesh function:
sub mesh (\#\#;\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#) {
my $max = -1;
$max < $#$_ && ($max = $#$_) for #_;
map { my $ix = $_; map $_->[$ix], #_; } 0..$max;
}
I find the following solution straightforward and easy to read:
#a = (1, 2, 3);
#b = ('apple', 'orange', 'grape');
#zipped = map {($a[$_], $b[$_])} (0 .. $#a);
I believe it's also faster than solutions that create the array in a wrong order first and then use slice to reorder, or solutions that modify #a and #b.
For arrays of the same length:
my #zipped = ( #a, #b )[ map { $_, $_ + #a } ( 0 .. $#a ) ];
my #l1 = qw/1 2 3/;
my #l2 = qw/7 8 9/;
my #out;
push #out, shift #l1, shift #l2 while ( #l1 || #l2 );
If the lists are a different length, this will put 'undef' in the extra slots but you can easily remedy this if you don't wish to do this. Something like ( #l1[0] && shift #l1 ) would do it.
Hope this helps!
Algorithm::Loops is really nice if you do much of this kind of thing.
My own code:
sub zip { #_[map $_&1 ? $_>>1 : ($_>>1)+($#_>>1), 1..#_] }
This is totally not an elegant solution, nor is it the best solution by any stretch of the imagination. But it's fun!
package zip;
sub TIEARRAY {
my ($class, #self) = #_;
bless \#self, $class;
}
sub FETCH {
my ($self, $index) = #_;
$self->[$index % #$self][$index / #$self];
}
sub STORE {
my ($self, $index, $value) = #_;
$self->[$index % #$self][$index / #$self] = $value;
}
sub FETCHSIZE {
my ($self) = #_;
my $size = 0;
#$_ > $size and $size = #$_ for #$self;
$size * #$self;
}
sub CLEAR {
my ($self) = #_;
#$_ = () for #$self;
}
package main;
my #a = qw(a b c d e f g);
my #b = 1 .. 7;
tie my #c, zip => \#a, \#b;
print "#c\n"; # ==> a 1 b 2 c 3 d 4 e 5 f 6 g 7
How to handle STORESIZE/PUSH/POP/SHIFT/UNSHIFT/SPLICE is an exercise left to the reader.