In trying to write a script to permute values in a list, I'm getting an uninitialized value warning - perl

I'm very unsure what is happening. For various lengths of #depths, the code generally works. However, throughout the output, at certain points the program barfs up complaints about use of an uninitialized value.
The errors blame line 20: print $chars[$depths[$y]];
I apologize ahead of time if it's something obvious, but I'm definitely missing the issue. I've googled for about an hour with no luck so any nudges in the right direction would be very appreciated!
Complete code:
#! /usr/bin/perl -w
use strict;
use warnings;
#my #chars = ("0" .. "9");
#my #depths = (0) x 4;
my #chars = ("0" .. "1");
my #depths = (0) x 3;
my ($i, $x, $y);
for ($i = 0; $i < #chars ** #depths; $i++) {
for ($y = 0; $y < #depths; $y++) {
print $chars[$depths[$y]];
}
print"\n";
$depths[$#depths]++;
for($x = 0; $x < #depths; $x++) {
if($depths[$x] == #chars) {
$depths[$x-1]++;
while($x < #depths) {
$depths[$x++] = 0;
}
}
}
}
Output:
000
001
010
011
Use of uninitialized value in print at a.pl line 15.
00
100
101
110

I added some print statements to your code, and the problem becomes apparent.
#! /usr/bin/perl -w
use strict;
use warnings;
my #chars = ("0".."1");
my #depths = (0) x 3;
my $i;
my $x;
my $y;
for ($i = 0; $i < #chars**#depths; $i++)
{
printf "m = %d\n", scalar(#depths);
for ($y = 0; $y < #depths; $y++)
{
print "y:$y; d[y] = $depths[$y]\n";
print " :$chars[$depths[$y]]:\n";
}
print"\n";
printf "b[%d] ", $depths[$#depths];
$depths[$#depths]++;
printf "a[%d]\n", $depths[$#depths];
for($x = 0; $x < #depths; $x++){
if($depths[$x] == #chars){
$depths[$x-1]++;
while($x < #depths){
$depths[$x++] = 0;
}
}
}
}
The output was:
m = 3
y:0; d[y] = 0
:0:
y:1; d[y] = 0
:0:
y:2; d[y] = 0
:0:
b[0] a[1]
m = 3
y:0; d[y] = 0
:0:
y:1; d[y] = 0
:0:
y:2; d[y] = 1
:1:
b[1] a[2]
m = 3
y:0; d[y] = 0
:0:
y:1; d[y] = 1
:1:
y:2; d[y] = 0
:0:
b[0] a[1]
m = 3
y:0; d[y] = 0
:0:
y:1; d[y] = 1
:1:
y:2; d[y] = 1
:1:
b[1] a[2]
m = 3
y:0; d[y] = 0
:0:
y:1; d[y] = 2
Use of uninitialized value within #chars in concatenation (.) or string at perm.pl line 18.
::
y:2; d[y] = 0
:0:
b[0] a[1]
m = 3
y:0; d[y] = 1
:1:
y:1; d[y] = 0
:0:
y:2; d[y] = 0
:0:
b[0] a[1]
m = 3
y:0; d[y] = 1
:1:
y:1; d[y] = 0
:0:
y:2; d[y] = 1
:1:
b[1] a[2]
m = 3
y:0; d[y] = 1
:1:
y:1; d[y] = 1
:1:
y:2; d[y] = 0
:0:
b[0] a[1]
The line immediately before the error report shows that $depths[$y] is 2, but the array #chars only contains elements with indexes 0 and 1, so the warning is accurate.

Think of #depths as a base N number (where N is the number of #chars), and each element of #depths is a digit. You're trying to add one to that number, but you're failing.
A carry propagates from the least significant digit to the most significant, so you should be the loop than handles the carry should loop from the least significant digit to the most significant, but you're doing it in the opposite order. $x should start at $#depth and decrease as the loop advances.
Let's look at an example. Say there are 10 symbols (#chars == 10):
456999 <- #depth
+ 1
-------
457000
So you want to increment the right-most digit that's not equal to $#chars, and set to zero all the right-most digits that are equal to $#chars. Here's how I coded that:
#!/usr/bin/perl -w
use strict;
use warnings;
my #chars = ("0".."2");
my #depths = (0) x 3;
OUTER: while (1) {
print #chars[#depths], "\n";
my $x = $#depths;
while ($depths[$x] == $#chars) {
$depths[$x] = 0;
last OUTER if $x == 0;
--$x;
}
++$depths[$x];
}

Related

how to get some alphabet on string array & count some alphabet in perl

for example:
Input: Testing 123 for my letter count program.
Output: t = 5 e = 3 g = 2 n = 2 c = 1 i = 1 p = 1 u = 1 r = 4 o = 3 m
= 2 a = 1 f = 1 l = 1 s = 1 y = 1
I try to code this question, but didn't worked. This is my code:
#!/usr/bin/perl
use utf8;
use warnings;
$line = <STDIN>;
$len = length($line);
$count = 0;
while($count < $len){
print "$line[$count]\n";
$count += 1;
}
So help me to code this question. Because i don't understand how to code this question
use strict;
use warnings;
my $input = 'Testing 123 for my letter count program.';
my %seen;
my #order = grep { !$seen{$_}++ } lc($input) =~ /([a-z])/ig;
print "$_ = $seen{$_}\n" for #order;
output
t = 5
e = 3
s = 1
i = 1
n = 2
g = 2
f = 1
o = 3
r = 4
m = 2
y = 1
l = 1
c = 1
u = 1
p = 1
a = 1
#!/usr/bin/perl
use strict; use warnings;
my $input = 'Testing 123 for my letter count program.';
my %hash = ();
map { $hash{lc($_)}++ } grep /[a-zA-Z]/, split('', $input);
print "Output: ";
print "$_ = $hash{$_} " for(keys %hash);
OUTPUT:
Output: e = 3 y = 1 a = 1 r = 4 s = 1 g = 2 c = 1 n = 2 l = 1 t = 5 i = 1 p = 1 f = 1 m = 2 u = 1 o = 3

Majority Element Failing to close cycles

I'm trying to figure out why this keeps printing the "majority element" candidate in every cycle.
The code I've been trying to make work is a Majority Element search (to find an element that is repeated more than half of the length of a list).
I can't separate the processes of finding the candidate and testing against the array because my input is a text file that has an indeterminate number of arrays. It's an exercise from rosalind.info that has different inputs every time you try to solve it.
An example of the input would be
-5 5 5 5 5 5 5 5 -8 7 7 7 1 7 3 7 -7 1 6 5 10 100 1000 1 -5 1 6 7 1 1 10 1
Here's what I've written so far.
foreach my $currentrow (#lists) {
my #row = ();
#row = split( /\s/, $currentrow );
my $length = $#row;
my $count = 0;
my $i = 0;
for $i ( 0 .. $length - 1 ) {
if ( $count == 0 ) {
$candidate = $row[$i];
$count++;
}
if ( ( $count > 0 ) and ( $i = $length - 1 ) ) {
my $counter2 = 0;
for my $j ( 0 .. $length - 1 ) {
if ( $row[$j] == $candidate ) {
$counter2++;
}
}
if ( $counter2 <= ( $#row / 2 ) and ( $i = $length - 1 ) ) {
$candidate = -1;
print $candidate, " ", $i, " ";
}
if ( $counter2 > ( $#row / 2 ) and ( $i = $length - 1 ) ) {
print $candidate, " ", $i, " ";
}
}
if ( $candidate == $row[$i] and $count > 0 ) {
$count = $count + 1;
}
if ( $candidate != $row[$i] and $count > 0 ) {
$count = $count - 1;
}
}
}
Do you have use strict and use warnings 'all' in place?
I imagine that your problem may be because of the test $i = $length - 1, which is an assignment, and should be $i == $length - 1
To find a majority element I would use a hash:
perl -nae '%h=(); $h{$_}+=2 for #F; $h{$_}>#F and print for keys %h; print "\n"'
Each line of input is treated separately. Each line of output matches a line of input and presents its majority element or is empty if there is no such element.
Edit: Now the solution uses autosplit (-a), which is shorter and work not only for numbers.

perl logical/conditional expression possible?

I need to proccess a waveform from a text file.
I need to remove an element only when Y2-Y1 < 30
Currently I run
s/[0-9.]{3,} [0-9.]{3,} m\n[0-9.]{3,} [0-9.]{3,} l\nS/0 0 m\n0 0 l\nS/g
but this removes more than I need. Is this even possible in perl?
The format is
X1 Y1 m
X2 Y2 l
S
Sample Data:
1560 5940 m
1560 5374 l
S
1548 5964 m
1572 5964 l
S
1572 5964 m
1572 5940 l
S
Desired output:
1560 5940 m
1560 5374 l
S
0 0 m
0 0 l
S
0 0 m
0 0 l
S
This expects to be called with your input filename as an argument:
use strict;
use warnings;
my #queue;
while (<>) {
next unless /\S/;
push(#queue, $_);
if (/^S/) {
my ($x1, $y1) = split(/\s+/, shift(#queue));
my ($x2, $y2) = split(/\s+/, shift(#queue));
if ($y2 - $y1 < 30) {
$x1 = $y1 = $x2 = $y2 = 0;
}
print "$x1 $y1 m\n$x2 $y2 l\nS\n\n";
#queue = ();
}
}
If it is looking like a record what about reading it like a records:
#!/usr/bin/env perl
use strict;
use warnings;
local $/ = "S\n\n";
while (<>) {
my ( $x1, $y1, $x2, $y2 ) = m/(\d+)\s+(\d+)\s+m\n(\d+)\s+(\d+)\s+l/;
next unless defined $x1;
$_ = "0 0 m\n0 0 l\nS\n\n" if $y1 - $y2 < 30;
}
continue {
print;
}
BTW, your example output doesn't correspond with your Y2-Y1 < 30 condition.
This sounds like a job for if() {} instead of regex.
Apologies if the following needs editing - my Perl is rusty.
My snippet assumes two input arrays #y1 and #y2, both of the same known length $array_length.
my $i = 0;
my $y1 = 0;
my $y2 = 0;
for ( i = 0; i < $array_length; i++ )
{
$y1 = $y1[i];
$y2 = $y2[i];
if ( $y2 - $y1 < 30 )
{
#your output code here
}
else
{
#output 0s here
}
}
There's ways to simplify that to have only one output block.

Formating a data form perl::DBI query

I have a script that downloads data from a database.
But I am having trouble formatting the data into rows.
#!/perl/bin/perl
use FOOConf;
FOOConf::makeDBConnection(production);
$dbh=$EVTConf::dbh;
use Data::Dumper ;
my %extend_hash = %{#_[0]};
my $query = "select level_id,e_risk_symbol,e_exch_dest,penny,specialist from etds_extend";
if(!$dbh) {
print "Error connecting to DataBase; $DBI::errstr\n";
}
my $cur_msg = $dbh->prepare($query) or die "\n\nCould not prepare statement: ".$dbh->errstr;
$cur_msg->execute();
my (#row);
while (#row = $cur_msg->fetchrow_array ) {
#foreach $row(#row) {
#print "$row \n" ;
printf "%-8s %-4s %-2s %-2s %-2s\n ", $row[0], $row[1], $row[2], $row[3], $row[4], $row[5];
#printf "%-12s %6.2f\n", $row[0], $row[3];
#for (my $i = 0; $i < scalar(#row); $i++) {
# printf "%-12s = %s\n", $cur_msg->{NAME}[$i], $row[$i];
# }
#}
}
i am using this to format the rows. The format is all mesed up
printf "%-8s %-4s %-2s %-2s %-2s\n ", $row[0], $row[1], $row[2], $row[3],
this is what the format is :
5 MRO CS 1 0
5 FFIV CS 1 0
5 GM CS 1 0
5 MCP CS 1 0
5 RVBD CS 1 0
6 OIS_SPIN XISX 0 1
6 CVEO XISX 0 1
6 MRVL AMXO 0 1
6 MRX AMXO 0 1
6 MS XISX 0 1
6 MTG XISX 0 1
if I just use this loop
while (#row = $cur_msg->fetchrow_array ) {
foreach $row(#row) {
print "$row \n" ;
}
}
each row gets printed out one line at a time - the thread starts with a 5 - which seems to screw up the formatting. How do i factor this out first 5 ?
[ walt]$ ./test_db_data_format.very_simple | head -20
5
MRO
CS
1
0
5
FFIV
CS
1
0
5
GM
CS
1
0
5
MCP
CS
1
0
when i use I this loop this format - which is really nice.
That level id comes in at beginning without being attached to a symbol - screwing me up.
while (#row = $cur_msg->fetchrow_array ) {
for (my $i = 0; $i < scalar(#row); $i++) {
printf "%-12s = %s\n", $cur_msg->{NAME}[$i], $row[$i];
}
}
This is the results with the rows from the data base:
LEVEL_ID = 5
E_RISK_SYMBOL = MRO
E_EXCH_DEST = CS
PENNY = 1
SPECIALIST = 0
LEVEL_ID = 5
E_RISK_SYMBOL = FFIV
E_EXCH_DEST = CS
PENNY = 1
SPECIALIST = 0
LEVEL_ID = 5
E_RISK_SYMBOL = GM
E_EXCH_DEST = CS
PENNY = 1
SPECIALIST = 0
LEVEL_ID = 5
What I need is the E_RISK_SYMBOL to start and a newline after LEVEL_ID to start a new row.
It should look just like this just like this:
MRO CS 1 0 5
FFIV CS 1 0 5
GM CS 1 0 5
MCP CS 1 0 5
RVBD CS 1 0 6
OIS_SPIN XISX 0 1 6
It looks like your primary problem was just a trailing space in your format string after the \n and the fact that you were printing the $row[0] first instead of last.
You can also simplify your code by including the my declaration in the while (COND) and also using an array slice instead of listing out a bunch of individual array elements.
while (my #row = $cur_msg->fetchrow_array ) {
printf "%-8s %-4s %-2s %-2s %-2s\n", #row[1..4,0];
}
Note: You were also passing 6 values to a format string with only 5 spots in your first code. If you actually want the 6th variable to be displayed, you'll have to specify its format as well.
while (#row = $cur_msg->fetchrow_array ) {
printf "%-8s %-4s %-2s %-2s %-2s\n", $row[1], $row[2], $row[3], $row[4], $row[0];
}
Personally, I'd probably fetch it as a hashref to aide in making it more readable/understandable/maintainable.
while (my $row = $cur_msg->fetchrow_hashref ) {
printf "%-8s %-4s %-2s %-2s %-2s\n", $row->{e_risk_symbol},
$row->{e_exch_dest},
$row->{penny},
$row->{specialist},
$row->{level_id};
}

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.