Perl: Create a binary number and convert it into hex - perl

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.

Related

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.

perl: sprintf for element in list

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);
}
}

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>.

Misunderstanding of incrementation

In Perl, I have this following code:
my $val = "0";
for(my $z = 0; $z <= 14; $z++)
{
++$val;
if($val == 9) {
$val = "A";
}
print $val;
}
it prints:
1 2 3 4 5 6 7 8 A B 1 2 3 4 5
yet it's supposed to continue from B to C, from C to D and so on, what is the logic behind this?
warnings would have given you a warning message like:
Argument "B" isn't numeric in numeric eq (==)
use warnings;
use strict;
my $val = "0";
for(my $z = 0; $z <= 14; $z++)
{
++$val;
if($val eq '9') { # <------------------
$val = "A";
}
print $val;
}
To quote perlop:
If you increment a variable that is numeric, or that has ever been used in a numeric context, you get a normal increment. If, however, the variable has been used in only string contexts since it was set, and has a value that is not the empty string and matches the pattern /^[a-zA-Z]*[0-9]*\z/, the increment is done as a string, preserving each character within its range, with carry... (emphasis added)
$val == 9 is a numeric context. So it prints A (you just set it), and then you get the magic increment to B (it hasn't been used in a numeric context yet), but then you hit the == (using it in a numeric context), so when you get to ++$val again B is treated as a number (0) and increments to 1.
You could use eq to make a string comparison, thus preserving the magic increment, but you could also just say:
print 1 .. 8, 'A' .. 'F';

Capturing Non-Zero Elements, Counts and Indexes of Sparse Matrix

I have the following sparse matrix A.
2 3 0 0 0
3 0 4 0 6
0 -1 -3 2 0
0 0 1 0 0
0 4 2 0 1
Then I would like to capture the following information from there:
cumulative count of entries, as matrix is scanned columnwise.
Yielding:
Ap = [ 0, 2, 5, 9, 10, 12 ];
row indices of entries, as matrix is scanned columnwise.
Yielding:
Ai = [0, 1, 0, 2, 4, 1, 2, 3, 4, 2, 1, 4 ];
Non-zero matrix entries, as matrix is scanned columnwise.
Yielding:
Ax = [2, 3, 3, -1, 4, 4, -3, 1, 2, 2, 6, 1];
Since the actual matrix A is potentially very2 large, is there any efficient way
in Perl that can capture those elements? Especially without slurping all matrix A
into RAM.
I am stuck with the following code. Which doesn't give what I want.
use strict;
use warnings;
my (#Ax, #Ai, #Ap) = ();
while (<>) {
chomp;
my #elements = split /\s+/;
my $i = 0;
my $new_line = 1;
while (defined(my $element = shift #elements)) {
$i++;
if ($element) {
push #Ax, 0 + $element;
if ($new_line) {
push #Ai, scalar #Ax;
$new_line = 0;
}
push #Ap, $i;
}
}
}
push #Ai, 1 + #Ax;
print('#Ax = [', join(" ", #Ax), "]\n");
print('#Ai = [', join(" ", #Ai), "]\n");
print('#Ap = [', join(" ", #Ap), "]\n");
A common strategy for storing sparse data is to drop the values you don't care about (the zeroes) and to store the row and column indexes with each value that you do care about, thus preserving their positional information:
[VALUE, ROW, COLUMN]
In your case, you can economize further since all of your needs can be met by processing the data column-by-column, which means we don't have to repeat COLUMN for every value.
use strict;
use warnings;
use Data::Dumper;
my ($r, $c, #dataC, #Ap, #Ai, #Ax, $cumul);
# Read data row by row, storing non-zero values by column.
# $dataC[COLUMN] = [
# [VALUE, ROW],
# [VALUE, ROW],
# etc.
# ]
$r = -1;
while (<DATA>) {
chomp;
$r ++;
$c = -1;
for my $v ( split '\s+', $_ ){
$c ++;
push #{$dataC[$c]}, [$v, $r] if $v;
}
}
# Iterate through the data column by column
# to compute the three result arrays.
$cumul = 0;
#Ap = ($cumul);
$c = -1;
for my $column (#dataC){
$c ++;
$cumul += #$column;
push #Ap, $cumul;
for my $value (#$column){
push #Ax, $value->[0];
push #Ai, $value->[1];
}
}
__DATA__
2 3 0 0 0
3 0 4 0 6
0 -1 -3 2 0
0 0 1 0 0
0 4 2 0 1
This is what you are looking for, I guess:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper::Simple;
my #matrix;
# Populate #matrix
while (<>) {
push #matrix, [ split /\s+/ ];
}
my $columns = #{ $matrix[0] };
my $rows = #matrix;
my ( #Ap, #Ai, #Ax );
my $ap = 0;
for ( my $j = 0 ; $j <= $rows ; $j++ ) {
for ( my $i = 0 ; $i <= $columns ; $i++ ) {
if ( $matrix[$i]->[$j] ) {
$ap++;
push #Ai, $i;
push #Ax, $matrix[$i]->[$j];
}
}
push #Ap, $ap;
}
print Dumper #Ap;
print Dumper #Ai;
print Dumper #Ax;
Updated based on FM's comment. If you do not want to store any of the original data:
#!/usr/bin/perl
use strict;
use warnings;
my %matrix_info;
while ( <DATA> ) {
chomp;
last unless /[0-9]/;
my #v = map {0 + $_ } split;
for (my $i = 0; $i < #v; ++$i) {
if ( $v[$i] ) {
push #{ $matrix_info{$i}->{indices} }, $. - 1;
push #{ $matrix_info{$i}->{nonzero} }, $v[$i];
}
}
}
my #cum_count = (0);
my #row_indices;
my #nonzero;
for my $i ( sort {$a <=> $b } keys %matrix_info ) {
my $mi = $matrix_info{$i};
push #nonzero, #{ $mi->{nonzero} };
my #i = #{ $mi->{indices} };
push #cum_count, $cum_count[-1] + #i;
push #row_indices, #i;
}
print(
"\#Ap = [#cum_count]\n",
"\#Ai = [#row_indices]\n",
"\#Ax = [#nonzero]\n",
);
__DATA__
2 3 0 0 0
3 0 4 0 6
0 -1 -3 2 0
0 0 1 0 0
0 4 2 0 1
Output:
C:\Temp> m
#Ap = [0 2 5 9 10 12]
#Ai = [0 1 0 2 4 1 2 3 4 2 1 4]
#Ax = [2 3 3 -1 4 4 -3 1 2 2 6 1]
Ap is easy: simply start with zeroes and increment each time you meet a nonzero number. I don't see you trying to write anything into #Ap, so it's no surprise it doesn't end up as you wish.
Ai and Ax are trickier: you want a columnwise ordering while you're scanning rowwise. You won't be able to do anything in-place since you don't know yet how many elements the columns will yield, so you can't know in advance the elements' position.
Obviously, it would be a hell lot easier if you could just alter the requirement to have a rowwise ordering instead. Failing that, you could get complex and collect (i, j, x) triplets. While collecting, they'd naturally be ordered by (i, j). Post-collection, you'd just want to sort them by (j, i).
The code you provided works on a row-by-row basis. To get results sequential by columns you have to accumulate your values into separate arrays, one for each column:
# will look like ([], [], [] ...), one [] for each column.
my #columns;
while (<MATRIX>) {
my #row = split qr'\s+';
for (my $col = 0; $col < #row; $col++) {
# push each non-zero value into its column
push #{$columns[$col]}, $row[$col] if $row[$col] > 0;
}
}
# now you only need to flatten it to get the desired kind of output:
use List::Flatten;
#non_zero = flat #columns;
See also List::Flatten.