I have this perl code below:
use strict;
use warnings;
sub powerset(&#) {
my $callback = shift;
my $bitmask = '';
my $bytes = #_/8;
{
my #indices = grep vec($bitmask, $_, 1), 0..$#_;
$callback->( #_[#indices] );
++vec($bitmask, $_, 8) and last for 0 .. $bytes;
redo if #indices != #_;
}
}
powerset { print "[#_]\n" } 1..21;
I'm trying to figure out how I can only run n times (say 6 times the powerset subroutine). i tried use it:
$x = 0;
while ($x <= 6) {
$x ++;
powerset() ;
}
On run 6 times I mean run to the sixth printed line, in this case to powerset {print "[#_]\n"} 1..21; matches up to the impression of
[]
[1]
[2]
[1 2]
[3]
[1 3]
[2 3]
But I don't know where I would apply it $x = 0; while ($x <= 6) { $x ++; powerset() ; }, if inside the sub powerset() or outside, it seems to me that inside the sub because where the routine is happening.
i know i should use die or return to get out of running a subroutine and that somewhere in while i should use maybe else, but i still don't see how to structure this in the code.
I feel that I should better understand the function of the variables $bitmask, $bytes, $callback, because as it is a lazy evaluation, the way of counting the execution is different.
Further research on how to run a perl subroutine leads me to questions about using timers that depend on the elapsed time in seconds rather than the number of times the subroutine is executed.
Here is an example of how you can constrain the number of times the callback is called:
use feature qw(state);
use strict;
use warnings;
sub powerset(&#) {
my $callback = shift;
my $bitmask = '';
my $bytes = #_/8;
{
my #indices = grep vec($bitmask, $_, 1), 0..$#_;
$callback->( #_[#indices] );
++vec($bitmask, $_, 8) and last for 0 .. $bytes;
redo if #indices != #_;
}
}
my $limit = 6;
powerset
{
state $counter = 0;
die "limit reached" if ++$counter > $limit;
print "[#_]\n"
}
1..21;
Related
I'm having a problem coding my first Perl program.
What I'm trying to do here is getting the maximum, minimum,total and average of a list of numbers using a subroutine for each value and another subroutine to print the final values. I'm using a "private" for all my variables, but I still couldn't print my values.
Here is my code:
&max(<>);
&print_stat(<>);
sub max {
my ($mymax) = shift #_;
foreach (#_) {
if ( $_ > $mymax ) {
$mymax = $_;
}
}
return $mymax;
}
sub print_stat {
print max($mymax);
}
Please try this one:
use strict;
use warnings;
my #list_nums = qw(10 21 30 42 50 63 70);
ma_xi(#list_nums);
sub ma_xi
{
my #list_ele = #_;
my $set_val_max = '0'; my $set_val_min = '0';
my $add_all_vals = '0';
foreach my $each_ele(#list_ele)
{
$set_val_max = $each_ele if($set_val_max < $each_ele);
$set_val_min = $each_ele if($set_val_min eq '0');
$set_val_min = $each_ele if($set_val_min > $each_ele);
$add_all_vals += $each_ele;
}
my $set_val_avg = $add_all_vals / scalar(#list_ele) + 1;
print "MAX: $set_val_max\n";
print "MIN: $set_val_min\n";
print "TOT: $add_all_vals\n";
print "AVG: $set_val_avg\n";
#Return these values into array and get into the new sub routine's
}
Some notes
Use plenty of whitespace to lay out your code. I have tidied the Perl code in your question so that I could read it more easily, without changing its semantics
You must always use strict and use warnings 'all' at the top of every Perl program you write
Never use an ampersand & in a subroutine call. That hasn't been necessary or desirable since Perl 4 over twenty-five years ago. Any tutorial that tells you otherwise is wrong
Using <> in a list context (such as the parameters to a subroutine call) will read all of the file and exhaust the file handle. Thereafter, any calls to <> will return undef
You should use chomp to remove the newline from each line of input
You declare $mymax within the scope of the max subroutine, but then try to print it in print_stat where it doesn't exists. use strict and use warnings 'all' would have caught that error for you
Your max subroutine returns the maximum value that it calculated, but you never use that return value
Below is a fixed version of your code.
Note that I've read the whole file into array #values and then chomped them all at once. In general it's best to read and process input one line at a time, which would be quite possible here but I wanted to say as close to your original code as possible
I've also saved the return value from max in variable $max, and then passed that to print_stat. It doesn't make sense to try to read the file again and pass all of those values to print_stat, as your code does
I hope this helps
use strict;
use warnings 'all';
my #values = <>;
chomp #values;
my $max = max(#values);
print_stat( $max );
sub max {
my $mymax = shift;
for ( #_ ) {
if ( $_ > $mymax ) {
$mymax = $_;
}
}
return $mymax;
}
sub print_stat {
my ($val) = #_;
print $val, "\n";
}
Update
Here's a version that calculates all of the statistics that you mentioned. I don't think subroutines are a help in this case as the solution is short and no code is reusable
Note that I've added the data at the end of the program file, after __DATA__, which lets me read it from the DATA file handle. This is often handy for testing
use strict;
use warnings 'all';
my ($n, $max, $min, $tot);
while ( <DATA> ) {
next unless /\S/; # Skip blank lines
chomp;
if ( not defined $n ) {
$max = $min = $tot = $_;
}
else {
$max = $_ if $max < $_;
$min = $_ if $min > $_;
$tot += $_;
}
++$n;
}
my $avg = $tot / $n;
printf "\$n = %d\n", $n;
printf "\$max = %d\n", $max;
printf "\$min = %d\n", $min;
printf "\$tot = %d\n", $tot;
printf "\$avg = %.2f\n", $avg;
__DATA__
7
6
1
5
1
3
8
7
output
$n = 8
$max = 8
$min = 1
$tot = 38
$avg = 4.75
I am trying to write a subroutine that will receive an array reference and then delete some of the elements of the array. For example:
use strict;
use warnings;
my #a = (1, 2, 3, 6);
func1 (\#a);
sub func1 {
my $a = shift;
my #b = (2, 6);
for my $val_to_remove (#b) {
for my $i (0..$#$a) {
my $val = $a->[$i];
if ( $val == $val_to_remove ) {
splice #$a, $i, 1;
last;
}
}
}
}
This seems, to say the least, a little awkward using two for loops.
Is it possible to simplify this?
I also tried
use strict;
use warnings;
my #a = (1, 2, 3, 6);
my $temp = \#a;
func2 (\$temp );
sub func2 {
my $a = shift;
$$a = [2, 6];
}
but then #a is not modified, but rather $temp will be..
I would also rather like to avoid passing a reference to a reference, since that will mess up the calling syntax for other modules.
Use a hash as an indicator function for identifying efficiently the items to be removed; use a grep for filtering them out:
sub func1 {
my $a = shift;
my %b = map { ($_ => 1) } (2, 6);
#$a = grep { !$b{$_} } #$a;
}
Loic's solution works well and is quite readable. I would recommend it unless you're working with large arrays that cause the grep to eat a lot of memory, or if performance is absolutely critical.
You can get a bit of a performance boost by using splice:
use strict;
use warnings;
use Data::Dump;
my #haystack = (1, 2, 3, 6);
my %needle = map { $_ => 1 } (2, 6);
foreach my $i (reverse 0 .. $#haystack) {
splice #haystack, $i, 1 if exists $needle{ $haystack[$i] };
}
dd \#haystack;
Output:
[1, 3]
Note that you must iterate through #haystack in reverse order, since every time you remove an element, the remaining elements shift to the left, changing the array indexes.
Benchmark
Here are the results from a slightly modified version of BrowserUk's corrected benchmark, written in response to foreach array - delete current row ? on PerlMonks. The original benchmark included several other methods for removing elements from an array, which I've left out for simplicity.
$ ./benchmark -N=1e2
Rate grep for_splice
grep 40959/s -- -37%
for_splice 65164/s 59% --
$ ./benchmark -N=1e3
Rate grep for_splice
grep 4072/s -- -38%
for_splice 6515/s 60% --
$ ./benchmark -N=1e4
Rate grep for_splice
grep 366/s -- -33%
for_splice 550/s 50% --
$ ./benchmark -N=1e5
Rate grep for_splice
grep 32.7/s -- -38%
for_splice 52.9/s 62% --
$ ./benchmark -N=1e6
(warning: too few iterations for a reliable count)
Rate grep for_splice
grep 2.36/s -- -28%
for_splice 3.28/s 39% --
And the benchmark code itself:
#!/usr/bin/perl -sl
use strict;
use warnings;
use Benchmark 'cmpthese';
our $N //= 1e3;
our $I //= -1;
# 10% the size of the haystack
my $num_needles = int($N / 10) || 1;
our #as;
#{ $as[ $_ ] } = 1 .. $N for 0 .. 4;
our %needle = map { int(rand($N)) => 1 } 1 .. $num_needles;
cmpthese $I, {
for_splice => q[
my $ar = $as[0];
foreach my $i (reverse 0 .. $#$ar) {
splice #$ar, $i, 1 if exists $needle{ $ar->[$i] };
}
$I == 1 and print "0: ", "#$ar";
],
grep => q[
my $ar = $as[1];
#$ar = grep { ! exists $needle{$_} } #$ar;
$I == 1 and print "1: ", "#$ar";
],
};
You can't use a simple for (LIST) loop to iterate over the indices of an array if you're also modifying the contents of the array. That's because the index of the last item may change, and you will also skip over elements if you delete the current element and increment the counter.
A while loop is required instead, or the equivalent C-style for.
This program demonstrates, as well as uing List::Util::any to check whether an array elemnent should be deleted
use strict;
use warnings;
use List::Util 'any';
my #a = (1, 2, 3, 6);
func1 (\#a);
use Data::Dump;
dd \#a;
sub func1 {
my ($a) = #_;
my #b = (2, 6);
for ( my $i = 0; $i < #$a; ) {
if ( any { $a->[$i] == $_ } #b ) {
splice #$a, $i, 1;
}
else {
++$i;
}
}
}
output
[1, 3]
With problems of this nature, it is often easier to build the array you want rather than delete from an existing one.
my #a = ( 1, 2, 3, 6 );
sub func1 {
my $aref = shift #_;
my #b = ( 2, 6 );
my #results = ();
for my $item ( #$aref ){
if( grep { $item == $_ } #b ){
next;
}
push #results, $item;
}
return #results;
}
my #results = func1( \#a );
say "#results";
For a given value N I am trying to output the corresponding Fibonacci number F(N). My script doesn't seem to enter the recursive stage. fibonnaci($number) is not calling the subroutine. It is simply outputing "fibonacci(whatever number is inputted)".
Here is my code:
#!/usr/bin/perl -w
use warnings;
use strict;
print "Please enter value of N: ";
my $number = <STDIN>;
chomp($number);
sub fibonacci
{
my $f;
if ( $number == 0 ) { # base case
$f = 0;
} elsif ( $number == 1 ) {
$f = 1;
} else { # recursive step
$f = fibonacci( $number - 1 ) + fibonacci( $number - 2 );
}
return $f;
}
print "\nf($number) = fibonacci($number)\n";
Sample Output:
Please enter value of N: 4
f(4) = fibonacci(4)
user1:~>recursiveFib.pl
Please enter value of N: 5
f(5) = fibonacci(5)
user1:~>recursiveFib.pl
Please enter value of N: 10
f(10) = fibonacci(10)
user1:~>
Not sure where I went wrong. Any help would be greatly appreciated.
You need to accept the function arguments properly and take the function call out of the quotes.
use warnings;
use strict;
sub fibonacci {
my ($number) = #_;
if ($number < 2) { # base case
return $number;
}
return fibonacci($number-1) + fibonacci($number-2);
}
print "Please enter value of N: ";
my $number = <STDIN>;
chomp($number);
print "\n$number: ", fibonacci($number), "\n";
A more efficient but still recursive version:
sub fib_r {
my ($n,$a,$b) = #_;
if ($n <= 0) { return $a; }
else { return fib_r($n-1, $b, $a+$b); }
}
sub fib { fib_r($_[0], 0, 1); } # pass initial values of a and b
print fib(10), "\n";
Other answers have already mentioned the lack of taking an argument correctly to the fibonacci function, and that you can't interpolate a function call in the print string like that. Lately my favourite way to interpolate function calls into print strings is to use the ${\ ... } notation for embedding arbitrary expressions into strings:
print "f($number) = ${\ fibonacci($number) }\n";
Other techniques include separate arguments:
print "f($number) = ", fibonacci($number), "\n";
or a helper variable:
my $result = fibonacci($number);
print "f($number) = $result\n";
or even printf:
printf "f(%d) = %d\n", $number, fibonacci($number);
Of all these techniques I tend to prefer either of the first two, because they lead to putting the expressions "in-line" with the rest of the text string, whereas in the latter two they sit elsewhere, making it harder to see at a glance what gets printed where. Especially with printf's positional arguments, it can be easy to be "off-by-one" with a large number of arguments, and put everything in the wrong place.
You are printing in wrong way. you just need to handle the return value. Also the way you are using Number in the sub is also not seems relevant. I have updated the and its working fine.
Also the values that you wanted to print is depend on the start up of the series. whether you want to start from 0 or 1.
The series example start with 1 is 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, so if you put 10 you will get 55.
#!/usr/bin/perl -w
use warnings;
use strict;
print "Please enter value of N: ";
my $number = <STDIN>;
chomp($number);
my $result=fibonacci($number);
sub fibonacci
{
my $f =0;
if ($_[0] == 1 ) { # base case
$f = 1;
} elsif ( $_[0] == 2 ) {
$f = 1;
} else { # recursive step
$f= fibonacci( $_[0] - 1 ) + fibonacci( $_[0] - 2 );
}
return $f;
}
print "\nf($number) = $result\n";
I'm trying to construct a permutation program in Perl using the NestedLoops function. Here's my code:
use strict;
use warnings;
use Algorithm::Loops qw(NestedLoops);
my #a = 'a'..'o';
my $length = 5;
my $start = 0;
my $depth = 2;
NestedLoops([
[0..$length],
( sub {
$start = 0 if $start == $depth;
$start++;
[$start * $length..$start * $length + $length - 1]
}) x $depth,
], \&permute,);
sub permute {
my #ind = #_;
foreach my $i (#ind) {
print $a[$i];
}
print "\n";
}
So I've got an array that holds the letters 'a' to 'o' (size being 15). I'm treating the array as if it had 3 rows, so my imagination of the array is this:
abcde
fghij
klmno
Then each loop corresponds to each row... and I want to build permutations like:
afk
afl
afm
afn
afo
agk // fails here... I end up getting agg
...
It works for the first 5 values (the entire run of the lowest for loop), but then the second run fails because the last row's value of $start gets reset to 0... this is a problem because that breaks everything.
So what I want to know is, how can I keep the value of $start persistent based on the level... So what I'm asking for is essentially having constants. My loops really should look like this:
for my $a (0..5) { # 0 at this level and never change
for my $b (5..10) { # $start should be 5 at this level and never change
for my $c (10..15) { # $start should be 10 at this level and never change
permute($a, $b, $c);
}
}
}
Now, because I will have a variable length of for loops, I can't hard code each start value, so I'm looking for a way to initially create those start values, and then keep them for when the loop gets reset.
I realize this is a confusing question, so please ask questions, and I will help clarify.
You are making this harder than it has to be.
Part of the problem is that the documentation for NestedLoops doesn't go into much detail about how a subroutine reference in the first argument, will be used.
For the following examples, assume this is written somewhere above them.
use strict;
use warnings;
use Algorithm::Loops qw'NestedLoops';
Really the simplest way to call NestedLoops to get what you want is like this:
NestedLoops(
[
['a'..'e'],
['f'..'j'],
['k'..'o'],
],
\&permute
);
sub permute {
print #_, "\n";
}
If you really want the arguments to NestedLoops to be generated on the fly, I would recommend using part from List::MoreUtils.
use List::MoreUtils qw'part';
my #a = 'a'..'o';
my $length = 5;
my $index;
NestedLoops(
[
part {
$index++ / $length
} #a
],
\&permute
);
sub permute {
print #_, "\n";
}
If for some reason you want to call NestedLoops with indexes into the array, It is still easy with part.
use List::MoreUtils qw'part';
my #a = 'a'..'o';
my $length = 5;
NestedLoops(
[
part {
$_ / $length
} 0..#a-1
],
\&permute
);
sub permute {
print map { $a[$_] } #_;
print "\n";
}
Really the main problem you're having is that the two subroutine references that you give to NestedLoops are modifying the same variables, and they are both called multiple times.
The best way to fix this is to rely on the last value given to the subroutine when it is called. ( From looking at the implementation, this seems to be closer to how it was meant to be used. )
my #a = 'a'..'o';
my $length = 5;
my $depth = 3;
NestedLoops(
[
[0..$length-1],
(sub{
return unless #_;
my $last = pop;
my $part = int( $last / $length ) + 1; # current partition
my $start = $part * $length; # start of this partition
my $end = $start + $length;
[$start..$end-1] # list of variables in this partition
}) x ($depth-1)
],
\&permute
);
sub permute {
print map { $a[$_] } #_;
print "\n";
}
When you use a subroutine to generate the range of a loop, it is called every time that one of the nested loops must start. That means once for each iteration of the containing loop. Before each call $_ is set to the current value of the containing loop's variable, and the values of all the containing loop variables are passed as parameters.
To clarify this, the NestedLoops statement you have coded is equivalent to
sub loop_over {
$start = 0 if $start == $depth;
$start++;
[$start * $length..$start * $length + $length - 1]
};
NestedLoops([
[0..$length],
(\&loop_over) x $depth,
], \&permute,);
which, in raw Perl, looks something like
for my $i (0 .. $length) {
$_ = $i;
my $list = loop_over($i);
for my $j (#$list) {
$_ = $j;
my $list = loop_over($i, $j);
for my $k (#$list) {
permute($i, $j, $k);
}
}
}
so perhaps it is clearer now that your calculation of $start is wrong? It is reevaluated several times for the innermost level before execution ascends to restart the containing loop.
Since the parameters passed to the subroutine consist of all the values of the containing loop variables, the size of #_ can be checked to see for which level of the loop to generate a range. For instance, in the code above, if #_ contains two values they are $i and $j, so the values for $k must be returned; alternatively, if there is only one parameter then it is the value of $i, and the returned value must be the range for $j. So the correct value for your $start is simply the number of elements in #_ and can be set using my $start = #_;.
Using this method the subroutine can return the range for the outermost loop as well. The code looks like this
use strict;
use warnings;
use Algorithm::Loops qw(NestedLoops);
my #a = 'a'..'o';
my $length = 5;
my $start = 0;
my $depth = 2;
NestedLoops([
(sub {
$start = #_;
[$start * $length .. $start * $length + $length - 1];
}) x ($depth + 1)
], \&permute,);
sub permute {
print map { $a[$_] } #_;
print "\n";
}
I have some code that reads from a file, and outputs the Fibonacchi numbers. E.g: 5 = 1, 1, 2, 3, 5
How can I make my code ONLY print out the last value?
Thanks
#!/usr/bin/perl
use strict;
my $fibFile = shift;
if (!defined($fibFile)) {
die "[*] No file specified...\n";
}
open (FILE, "<$fibFile");
my #numbers = <FILE>;
foreach my $n (#numbers) {
my $a = 1;
my $b = 1;
for (0..($n - 1)) {
print "$a\n";
($a, $b) = ($b,($a + $b));
}
print "\n";
}
close (FILE);
I suggest using a subroutine to take a chunk of code out of the loop
sub fib {
my $n = shift();
my #fib = (1, 1);
push #fib, $fib[-1] + $fib[-2] while #fib < $n;
#fib[0 .. $n-1];
}
for my $n (1 .. 5) {
printf "%d = %s\n", $n, join ', ', fib $n;
}
Do you need to recalculate the Fibonacci series for every value in the file? If not then just move the #fib array declaration outside the subroutine and the data won't need to be recalculated.
I'm sorry I didn't answer the question! To print out only the last value in the sequence, change the loop limit in your code to $n-2 and move the line print "$a\n"; outside the loop to replace the line print "\n";