Nested for loop in perl - perl

I'm trying to make a little script with a nested "for" loop in perl.
As I'm learning, at first I've done 3 for loops and it worked well. In order to make something more intelligent, I'd like to nested them but I don't know what is wrong.
If my input text is ABCDEFGHI
I'd like to obtain
text 1 ABC DEF GHI
text 2 BCD EFG HI
text 3 CDE FGH I
But instead of it, my output is
text1 ABC DEF GHI ABC DEF GHI ABC DEF GHI ABC DEF GHI ABC DEF GHI ABC DEF GHI ABC DEF GHI ABC DEF GHI ABC DEF GHI
text2 BCD EFG HI BCD EFG HI BCD EFG HI
text3 CDE FGH I
Here is my script. I'm using perl 5.18.1.
use Modern::Perl '2013';
my #text1;
my #text2;
my #text3;
my $entry = shift;
my $len = length $entry;
for (my $i = 2; $i < $len; $i += 3) {
for (my $i = 1; $i < $len; $i += 3) {
for (my $i = 0; $i < $len; $i += 3) {
my $text = substr($entry, $i, 3);
push #text1, uc($text);
}
my $text = substr($entry, $i, 3);
push #text2, uc($text);
}
my $text = substr($entry, $i, 3);
push #text3, uc($text);
}
say "text1 #text1";
say "text2 #text2";
say "text3 #text3";
I've already taken a look around and here http://perldoc.perl.org/perlsyn.html#For-Loops
Thank you for any help

I don't know why you'd want three nested loops (not counting substr). You only need two: One loop to determine the starting position, and one to walk through the string.
my $text = uc('ABCDEFGHI');
for my $offset (0..2) {
my #parts;
for (my $i=$offset; $i<length($text); $i+=3) {
push #parts, substr($work, $i, 3);
}
say "#parts";
}
Or without substr. to truly demonstrate there are really only two loops:
my $text = uc('ABCDEFGHI');
my #text = split //, $text;
for my $offset (0..2) {
my #parts;
for my $i ($offset..$#text) {
$parts[ ($i - $offset) / 3 ] .= $text[$i];
}
say "#parts";
}
Personally, I'd use
my $text = uc('ABCDEFGHI');
for (1..3) {
my #parts = $text =~ /\G.{1,3}/sg;
say "#parts";
$text =~ s/^.//s;
}

Your three loops do not need to be nested to get your desired output:
use Modern::Perl '2013';
my #text1;
my #text2;
my #text3;
my $entry = shift;
my $len = length $entry;
for (my $i = 0; $i < $len; $i += 3) {
my $text = substr($entry, $i, 3);
push #text1, uc($text);
}
for (my $i = 1; $i < $len; $i += 3) {
my $text = substr($entry, $i, 3);
push #text2, uc($text);
}
for (my $i = 2; $i < $len; $i += 3) {
my $text = substr($entry, $i, 3);
push #text3, uc($text);
}
say "text1 #text1";
say "text2 #text2";
say "text3 #text3";
You could also re-factor this a little, using two nested loops:
use Modern::Perl '2013';
my #texts = ( [], [], [] );
my $entry = shift;
my $len = length $entry;
for ( my $start = 0; $start < 3; $start++ ) {
for ( my $i = $start; $i < $len; $i += 3 ) {
my $text = substr($entry, $i, 3);
push #{$texts[$start]}, uc($text);
}
}
for ( my $start = 0; $start < 3; $start++ ) {
say "text${start} #{$texts[$start]}";
}
As an aside: If you do nest for loops, it will be easier to read and understand your code if you use a different variable as the iterator. The three $i variables you have will work, but I had to check quite a while to make sure that wasn't your problem.

Related

Unable to modify array parameter

This is supposed to put the contents of nums into decreasing order, however sort does not change the contents of nums. Many sites I read have said to pass by reference, but I don't think I'm dereferencing the argument correctly. Bear with me, this is my first Perl program :)
#! /usr/bin/env perl
sub sort {
my #arr = #_;
my $len = scalar #arr;
for (my $i = 1; $i < $len-1; $i = $i + 1) {
my $max = $i;
for (my $j = $i + 1; $j < $len; $j = $j + 1) {
if ($arr[$j] > $arr[$max]) {
$max = $j
}
}
$temp = $arr[$max];
$arr[$max] = $arr[$i];
$arr[$i] = $temp;
}
}
print "Enter 10 numbers: ";
my $numbers = <STDIN>;
my #nums = split ' ', $numbers;
print "Unsorted: #nums\n";
sort \#nums;
print "Sorted: #nums\n";
#Matt Jacob helped me out with this one. This is what I was looking for.
#! /usr/bin/env perl
sub selection_sort {
my $arr = shift;
my $len = scalar #$arr;
for (my $i = 0; $i < $len-1; $i++) {
my $max = $i;
for (my $j = $i + 1; $j < $len; $j++) {
if (#$arr[$j] > #$arr[$max]) {
$max = $j
}
}
my $temp = #$arr[$max];
#$arr[$max] = #$arr[$i];
#$arr[$i] = $temp;
}
}
print "Enter 10 numbers: ";
my $input = <STDIN>;
my #integers = split ' ', $input;
print "Unsorted: #integers\n";
selection_sort \#integers;
print "Sorted: #integers\n";

how to output into a tree like structure via Tree::DAG_Node?

I'm trying to write a program that can read from a file then put into a heap sort then output in a tree along with the sorted list. But I got stuck, instead of having the put be the numbers used in the heap sort, it just post 1-10 on one line then 1-9 on the next line. I'm really confused and I barely understand this language as it is. I put a example of the out below alone with the output I am hoping to have it draw.
#!/usr/bin/perl
use 5.006;
use strict;
use warnings;
use Tree::DAG_Node;
process_data(read_file('testing.txt'));
process_data((3,1,4,1,5,9,2,6,5,3,6));
sub read_file{
my($filename)=#_;
my #data=();
my #words;
open(my $fh, "<", $filename)
or die "Could not open file: $!\n";
while(<$fh>){
chomp;
#words = split(' ');
foreach my $word(#words){
push #data, $word;
}
}
close $fh;
return #data;
}
sub heap_sort {
my ($a) = #_;
my $n = #$a;
for (my $i = ($n - 2) / 2; $i >= 0; $i--) {
down_heap($a, $n, $i);
}
for (my $i = 0; $i < $n; $i++) {
my $t = $a->[$n - $i - 1];
$a->[$n - $i - 1] = $a->[0];
$a->[0] = $t;
down_heap($a, $n - $i - 1, 0);
}
}
sub down_heap {
my ($a, $n, $i) = #_;
while (1) {
my $j = max($a, $n, $i, 2 * $i + 1, 2 * $i + 2);
last if $j == $i;
my $t = $a->[$i];
$a->[$i] = $a->[$j];
$a->[$j] = $t;
$i = $j;
}
sub max {
my ($a, $n, $i, $j, $k) = #_;
my $m = $i;
$m = $j if $j < $n && $a->[$j] > $a->[$m];
$m = $k if $k < $n && $a->[$k] > $a->[$m];
return $m;
}
}
sub draw_tree{
my(#data)=#_;
my $root = Tree::DAG_Node->new;
$root->name($_[0]);
$root->new_daughter->name($_) for (1..10);
my #names = #data;
my $count = 50;
for my $n ($root->daughters) {
for (split //, $names[$count++]) {
$n->new_daughter->name($_)
}
}
print map "$_\n", #{$root->draw_ascii_tree};
}
sub process_data{
my(#data)=#_;
my #a = #data;
print "#a\n";
print "\n";
heap_sort(\#a);
draw_tree(#a);
print "\n";
print "#a\n";
print "\n";
}
here is the output I get
CMD output of my code
Output I am expecting:
(using example data)
1 1 9 4 5
1
|
1 ----- 9
|
/\
4 5
1 1 4 5 9

modify this code to print elements that differ a x number from previous position

I wrote this code to find substrings every x elements:
print "enter file path\n";
$letters = <>;
chomp ($letters);
$sequence = "";
open (LETTERS, $letters) or die "error opening\n";
print "how many letters at a shot\n";
$number = <>;
chomp ($number);
$size = length $sequence;
chomp ($size);
for ($i = 0; $i < $size; $i++) {
$test = substr ($sequence, $i, $number);
print "> Test $i\n";
print "$test\n";
if ($i >= $size - $number) {
last;
}
}
so if I open a file with this string and choose x = 3:
abcdefg
I get this result:
> Test 0 abc
> Test 1 bcd
> Test 2 cde
> Test 3 def
> Test 4 efg
Each substring differs from one position from the previous substring, I'd like to be able to control this number and dislocate the substring by 2 for example. So the result would be:
> Test 0 abc
> Test 2 cde
> Test 4 efg
Any suggestions? Thanks
Add:
...
$step = <>;
...
And change:
for ($i = 0; $i < $size; $i++) {
to
for ($i = 0; $i < $size; $i+=$step) {
for ($i = 0; $i < $size; $i += 2) {

Transposing the matrix in perl

I am trying to perform a transpose on a data contained in a file. The data is as follows:
1 2 3 4 5
2 3 4 5 6
4 5 6 7 9
4 3 7 6 9
I am getting the result as follows which is incorrect. I am not getting the error in the code due to which the last column is not transposed properly. Any solution...
Code:
#!/usr/bin/perl
use strict;
use warnings;
my #dependent; # matrix of dependent variable
# Reading the data from text file to the matrix
open( DATA, "<example.txt" ) or die "Couldn't open file , $!"; #depenedent
# Storing data into the array in matrix form
while ( my $linedata = <DATA> ) {
push #dependent, [ split '\t', $linedata ];
}
my $m = #dependent;
#print "$m\n";
my $n = #{ $dependent[1] };
#print $n;
#print "Matrix of dependent variables Y \n";
for ( my $i = 0; $i < $m; $i++ ) {
for ( my $j = 0; $j < $n; $j++ ) {
#print $dependent[$i][$j]," ";
}
#print "\n";
}
my #transpose;
for ( my $i = 0; $i < $n; $i++ ) {
for ( my $j = 0; $j < $m; $j++ ) {
$transpose[$i][$j] = $dependent[$j][$i];
}
}
for ( my $i = 0; $i < $n; $i++ ) {
for ( my $j = 0; $j < $m; $j++ ) {
print $transpose[$i][$j], " ";
}
print "\n";
}
chomp your data when you read it, before you split it; your strange output is caused by the last element of each row of the input still having a newline attached.
Just as a side note, DATA isn't a very good name to pick for a filehandle; perl already defines a special builtin filehandle named DATA for reading data that's embedded in a script or a module, so using that name for yourself can lead to confusion :)

perl: bignum not working with STDIN

#!/usr/bin/perl
use bignum;
$line = <STDIN>;
( $arr[0], $arr[1], $n ) = split( / /, $line );
$i = 2;
sub func {
while ( $i < $n ) {
$t = $arr[ $i - 1 ];
$arr[$i] = $arr[ $i - 1 ] * $arr[ $i - 1 ] + $arr[ $i - 2 ];
$i = $i + 1;
}
return $arr[ $i - 1 ];
}
print func;
when i am setting manual value for $arr[1] then bignum is working fine but when the value is taken from STDIN then it is being printed as integer no BIGINt. can anyone explain why this is happening.
When you use strings in a numeric context, perl converts them using your C library's atof(). This is not changed by bignum. If you'd like your strings converted in a different manner, I'd recommend Math::BigFloat->new or Math::BigInt->new.