Concatenate scalar with array name - perl

I am trying to concatenate a scalar with array name but not sure how to do.
Lets say we have two for loops (one nested inside other) like
for ($i = 0; $i <= 5; $i++) {
for ($k = 0; $k <=5; $k++) {
$array[$k] = $k;
}
}
I want to create 5 arrays with names like #array1, #array2, #array3 etc. The numeric at end of each array represents value of $i when array creation in progress.
Is there a way to do it?
Thanks

If you mean to create actual variables, for one thing, its a bad idea, and for another, there is no point. You can simply access a variable without creating or declaring it. Its a bad idea because it is what a hash does, exactly, and with none of the drawbacks.
my %hash;
$hash{array1} = [ 1, 2, 3 ];
There, now you have created an array. To access it, do:
print #{ $hash{array1} };
The hash keys (names) can be created dynamically, just like you want, so it is easy to create 5 different names and assign values to them.
for my $i (0 .. 5) {
push #{ $hash{"array$i"} }, "foo";
}

You need to add {} and "" to characters, when they are used as variable or array/hash name.
Try this:
for ($i = 0; $i <= 5; $i++){
for ($k = 0; $k <=5; $k++){
${"array$k"}[$k] = $k;
}
}
print "array5[4] = $array5[4]
array5[5] = $array5[5]\n";
array5[4] =
array5[5] = 5

Related

using for loop, finding prime number between 1-100

I'd tried lots of ways to get rid of this problem but... I can't find what's the problem of this code.
I use Perl and I want to find the prime number between 1-100.
use strict;
my $i=0;
my $j=0;
my $count=0;
for ($i=0; $i<101; $i++)
{
for ($j=2; $j<$i; $j++)
{
if ($i%$j==0)
{
$count+=1;
}
}
if ($count==0)
{
print "$i\n";
}
}
There are a few things to think about as you use the Sieve of Eratosthenes. Armali already pointed out that you were reusing the value in $count because you had it in a higher scope, so it didn't reset for each number you wanted to check.
But, I reformatted your code a bit:
use v5.10;
NUM: for( my $i=1; $i < 101; $i++ ) {
DIVISOR: for( my $j=2; $j < $i; $j++ ) {
next NUM if $i%$j == 0;
}
say $i;
}
Instead of using a flag variable ($count) to figure out what to do, you can use loop controls. If you find any divisor, you know that you have found a non-prime and there's no need to continue. That is, you don't need to count divisors.
When you find one, stop and move on to the next number. To do that, I've labeled the looping constructs. That way, in the inner loop I can skip to the next iteration of the outer loop. And, usually, once I label one loop I label them all but you don't need to do that.
Once you figure that part out, you don't need to do so much work. Aside from 2, you know that all the even numbers are not prime. You don't need to check those. So, instead of being clever, I'll just break out 2 as a special case:
use v5.10;
say 2;
NUM: for( my $i = 3; $i < 101; $i += 2 ) {
DIVISOR: for( my $j=2; $j < $i; $j++ ) {
next NUM if $i%$j == 0;
}
say $i;
}
The inner loop is doing too much work too. None of the numbers that you are checking are even, so you don't need to check any even divisors (or those ending 5 once you choose 5). And, you only have to go half way, so you can stop when you get to the square root of the number.
#!perl
use v5.10;
say 2;
NUM: for( my $i = 3; $i < 101; $i += 2 ) {
my $stop_at = int sqrt $i;
DIVISOR: for( my $j=3; $j <= $stop_at; $j += 2 ) {
next NUM if $i % $j == 0;
}
say $i;
}
And, for a final flourish, I'll take the top number from the command-line arguments but default to 100. With that, the comparison in the outer loop changes to <=:
#!perl
use v5.10;
my $limit = $ARGV[0] // 100;
say 2;
NUM: for( my $i = 3; $i <= $limit; $i += 2 ) {
my $stop_at = int sqrt $i;
DIVISOR: for( my $j=3; $j <= $stop_at; $j += 2 ) {
next NUM if $i % $j == 0;
}
say $i;
}
But, ikegami notes in a comment that for my $x (0..$n-1) is more idiomatic. That doesn't easily handle step sizes larger than 1. You can do various things to multiply that number to get the candidate number, or ways to generate the list ahead of time (but that means you have the list all at once). I'll switch to a while instead, and assume that these other bits do their work properly.
The $get_number is some magic subroutine that always gives us back the next number, and the is_prime does what it does to make the determination:
while( my $n = $get_number->() ) {
say $n if is_prime($n);
}
Here's one way that might work. First, there's a nifty Perl regex trick to determine primes. It doesn't matter that I'm using that because you can change it to whatever you like because it's hidden behind is_prime. The biggest benefit here is that it's short (and a bit of a show off):
#!perl
use v5.10;
my $get_number = generate_sub( $ARGV[0] // 100 );
while( my $n = $get_number->() ) {
say $n if is_prime($n);
}
sub is_prime { ( '1' x $_[0] ) !~ /\A(11+?)\1+\z/ }
sub generate_sub {
my( $limit ) = #_;
sub {
state $queue = [ 2, 3 ];
return if $queue->[0] > $limit;
push $queue->#*, $queue->[-1] + 2;
shift $queue->#*;
}
}
The generate_sub is a bit more tricky. First, the 2 makes is a bit tricky. Second, Perl doesn't have a yield like Python or Ruby (would be nice). To get around that, I'll see a queue with the first two numbers then add the next number based on the last on (so, adding 2 to 3 gets 5, and so on). That gets around the unique interval from 2 to 3. This stops if the next number in the queue is above the one that you want.
But, that's a bit complicated and only there to handle the special case of 2. I've been playing with a different idiom lately although I'm not convinced its desirable.
The state is a way to declare a persistent lexical variable. It runs only on the first execution. We'll use a state to return the first 2 right away. Then, the next time we come around, that $rc statement doesn't run and $next has 3. From there, I get the current number (0+$next so it's not the same data), and increment $next in a list, but only return the first in that list. That's just a trick that condenses the if-else:
sub generate_sub {
my( $limit ) = #_;
sub {
state $rc = do { return 2 };
state $next = 3;
return $next <= $limit ? ( 0+$next, $next += 2 )[0] : ();
}
}
I don't recommend this for your problem, but you should consider a way to generate the list of numbers so it's not tightly coupled to the problem. That way, you can get rid of the looping constructs.
But, that's much more than you needed to know.
You initialized my $count=0; outside instead of inside the outer for loop.
Besides that, $i should start from 2 rather than 0.

Can I use the size of an array without having to place it in a variable

Currently I am doing this to read the individual contents of an array
my $size = #words;
for(my $x = 0; $x < $size, $x++)
{
print $words[$x];
}
Is there away to skip the $size assignment? A way to cast the array and have one less line?
i.e.
for(my $x = 0; $x < $(#word), $x++)
{
print $words[$x];
}
Can't seem to find the right syntax.
Thanks
Replace
for (my $i = 0; $i < $(#words), $i++) { ... $words[$i] ... }
with
for (my $i = 0; $i < #words; $i++) { ... $words[$i] ... }
Just like in your assignment, an array evaluated in scalar context produces its size.
That said, using a C-style loop is complex and wasteful.
A better solution if you need the index:
for my $i (0..$#words) { ... $words[$i] ... }
A better solution if you don't need the index:
for my $word (#words) { ... $word ... }
Yes, for has a built in array iterator and for and foreach are synonyms.
for my $word (#words) {
print $word;
}
This is the preferred way to iterate through arrays in Perl. C style 3 statement for-loops are discouraged unless necessary. They're harder to read and lead to bugs, like this one.
for(my $x = 0; $x < $size, $x++)
^
should be a ;
Better to use foreach, but to your specific question, #foo in scalar context resolves to the length of the array, and $#foo resolves to the index of the last element:
foreach my $word (#words) { ... } # preferred
for(my $i = 0; $i < #words; ++$i) { my $word = $words[$i]; ... } # ok sometimes
for(my $i = 0; $i <= $#words; ++$i) { my $word = $words[$i]; ... } # same thing
(assuming that you haven't played with $[, which you shouldn't do.)
The syntax that you are searching for is actually no syntax at all. If you use an array variable anywhere where Perl knows you should be using a scalar value (like as an operand to a comparison operator) then Perl gives you the number of elements in the array.
So, based on your example, this will work:
# Note: I've corrected a syntax error here.
# I replaced a comma with a semicolon
for (my $x = 0; $x < #words; $x++)
{
print $words[$x];
}
But there are several ways that we can improve this. Firstly, let's get rid of the ugly and potentially confusing C-style for loop and replace it with a far easier to understand foreach.
foreach my $x (0 .. #words - 1)
{
print $words[$x];
}
We can also improve on that #words - 1. Instead, we can use $#words which gives the final index in the array #words.
foreach my $x (0 .. $#words)
{
print $words[$x];
}
Finally, we don't really need the index number here as we're just using it to access each element of the array in turn. Far better to iterate over the elements of the array rather than the indexes.
foreach my $element (#words)
{
print $element;
}

Perl: scope and allocation of a named variable

Here is a little sample.
my %X = ();
for (my $i = 0; $i < 5; $i ++)
{
$X {$i} = [$i .. 4]; # the assignment: reference to an unnamed array
}
# this is just for output - you can ignore it
foreach (sort keys %X)
{
print "\n" . $_ . " = ";
foreach (#{$X {$_}})
{
print $_;
}
}
The output is like expected.
0 = 01234
1 = 1234
2 = 234
3 = 34
4 = 4
If I use a local variable for the assignment it will produce the same output - thats ok!
The memory for the list is always reallocated and not overwritten because #l is always new. There is still a reference to it in %X so no release is possible(or however the memory-managment in perl is working - I dont know).
for (my $i = 0; $i < 5; $i ++)
{
my #l = ($i .. 4); # inside
$X {$i} = \#l;
}
But can I produce the same output from above with using an outside variable?
Is that possible with some allocation trick - like to give it a new memory but not garbage the old one?
my %X = ();
my #l; # outside
for (my $i = 0; $i < 5; $i ++)
{
#l = ($i .. 4);
$X {$i} = \#l;
}
All hash-elements now the the content of the last loop.
0 = 4
1 = 4
2 = 4
3 = 4
4 = 4
Is it possible to get the output from the beginning with the outer variable?
No, it's not possible for each value of %X to be a reference to a different array, while at the same time all being a reference to the same array.
If you want each value of %X to be a reference to a same array, go ahead an allocate a single array outside of the loop.
If you want each value of %X to be a reference to a different array, you'll need to allocate a new array for each pass through the loop. This can be a named one (created using my), or an anonymous one (created using [ ]).
If you simply wanted to use the values within the outside #l so that every referenced array initially has the same value, you could use
my #a = #l;
$X{$i} = \#l;
or
$X{$i} = [ #l ];

Perl concatenate name of an array with an existing value

The question is like this:
I have a loop. And while I iterate this loop I want to create a number of arrays with the following names: array1 array2 array3...
I am wondering if there is a way to concatenate these names in perl
I tried something like this but I get an error
$i = 0;
while ($i <= 5) {
#array . $i = ();
$i++;
}
Yes, you can do this, but no, you should not do this.
What you should do instead is use an array of references to anonymous arrays:
#arrayrefs = ();
$i = 0;
while ($i <= 5) {
$arrayrefs[$i] = [];
$i++;
}
or, more tersely:
#arrayrefs = ([], [], [], [], [], []);
But for completeness' sake . . . you can do this, by using "symbolic references":
$i = 0;
while ($i <= 5) {
my $name = "array$i";
#$name = ();
$i++;
}
(of course, arrays default to the empty array anyway, so this isn't really needed . . .).
By the way, note that it's actually customary to use a for loop rather than a while loop for such simple cases. Either this:
for ($i = 0; $i <= 5; $i++) {
...
}
or this:
for $i (0 .. 5) {
...
}
You want to use hash,
use strict;
use warnings;
my %hash;
for my $i (1 .. 5) {
$hash{ "array$i" } = [];
}
Long story short: Why it's stupid to use a variable as a variable name

Variable scopes in coderefs if perl, need an explanation of strange behavior

Why are the values of $copy_of_i's returned by coderefs in the #coderefs the same?
use Modern::Perl;
my #coderefs = ();
for (my $i = 0; $i < 5; $i++){
push #coderefs, sub {
my $copy_of_i = $i;
return $copy_of_i;
};
}
say $coderefs[1]->();
say $coderefs[3]->();
I thought the $copy_of_i would be local for every coderef added to #coderefs and thus contain the current value of $i assigned to the $copy_of_i at the given iteration of the loop. But if we display the values of a couple of $copi_of_i's with 'say' we'll see that they have the same values as if the $copy_of_i wasn't local for every newly created coderef. Why?
You want to have different values associated with the closures, yet you only have the single variable $i for all the closures to capture. You need to create a variable for each closure to capture, so $copy_of_i should be created outside of the closure. Creating a copy when you call the closure is far too late; $i no longer contains the desired value at that point.
for (my $i = 0; $i < 5; $i++){
my $copy_of_i = $i;
push #coderefs, sub {
return $copy_of_i;
};
}
By the way, for my $i (0 .. 5) is preferred over for (my $i = 0; $i < 5; $i++), and it has the advantage of creating a new variable for each iteration of the loop, so you can simply use
my #coderefs;
for my $i (0 .. 4) {
push #coderefs, sub {
return $i;
};
}