I'm practicing my Perl on codefights.
I've seen someone in a previous task feed Eval a list to make an array.
#a = map eval s/\B/*/gr, 0 .. 10000;
Yet, when i try and feed eval a list it give me an error
my ($a,$b,$c)=(1,2,3);
return 1 if eval "$a$_$b==$c", for qw "+ - / *";
This line also does not work as expected.
my ($a, $b, $c) = #_;
#aa=map eval "$a $_ $b", for qw "+ - / *";
However, this works
my ($a,$b,$c)=(1,2,3);
for (qw "+ - / *")
{
return 1 if eval "$a$_$b==$c";
}
Can someone explain what the difference between the statements is?
Thanks
You misunderstand what your first example does.
my #a = map eval s/\B/*/gr, 0 .. 10000;
This does not pass a list to eval. The eval s/...// is the argument to map in the non-block form. This becomes more clear when you add parentheses.
my #a = map( eval( s/\B/*/gr ), 0 .. 10000 );
It will call the eval statement for every number, and return a list of results, which gets assigned to #a. The code adds an asterisk after every other digit and builds a list of the resulting strings.
In this code, you again misunderstand what the map does.
my ($a, $b, $c) = #_;
#aa=map eval "$a $_ $b", for qw "+ - / *";
The map is essentially an in-place for loop. Adding a postfix for doesn't do anything useful here. map will already iterate all elements in your list. The list in this case is "+", "-", "/", "*", which was created by the qw// operator.
Get rid of the for and it will work.
my ( $x, $y ) = ( 1, 2 );
my #results = map eval "$x $_ $y", qw "+ - / *";
The results of this are:
3,
-1,
0.5,
2
I suggest you read up on map.
Related
I have next code:
my $str = '';
new( (split ',', $str )[0] )
Here I split my $str and asks exactly one element from result list
But when check incoming data at #_ I see zero elements
Why function does not receive arguments?
I expect one element
Here is some code that tests what you say in your question.
#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
sub new {
say 'new() received ' . #_ . ' argument(s).';
say "The first argument was '$_[0].'" if #_;
}
my $str = 'one,two,three';
new( (split ',', $str )[0] );
When I run it, I get the following output:
$ perl split_test
new() received 1 argument(s).
The first argument was 'one.'
This seems to be working as expected. So it seems likely that your problem lies in parts of the code that you haven't shared with us.
It seems I found the answer.
Problem was because of special case when I slice empty list.
This special case is useful at while condition:
while ( ($home, $user) = (getpwent)[7,0] ) {
printf "%-8s %s\n", $user, $home;
}
Here is documentation for this
#a = ()[0,1]; # #a has no elements
#b = (#a)[0,1]; # #b has no elements
#c = (sub{}->())[0,1]; # #c has no elements
#d = ('a','b')[0,1]; # #d has two elements
#e = (#d)[0,1,8,9]; # #e has four elements
#f = (#d)[8,9]; # #f has two elements
I was trying to think in the right way to tackle this:
-I would to pass say, n elements array as argument to a subroutine. And for each element match two char types S and T and print for each element, the count of these letters. So far I did this but I am locked and found some infinite loops in my code.
use strict;
use warnings;
sub main {
my #array = #_;
while (#array) {
my $s = ($_ = tr/S//);
my $t = ($_ = tr/T//);
print "ST are in total $s + $t\n";
}
}
my #bunchOfdata = ("QQQRRRRSCCTTTS", "ZZZSTTKQSST", "ZBQLDKSSSS");
main(#bunchOfdata);
I would like the output to be:
Element 1 Counts of ST = 5
Element 2 Counts of ST = 6
Element 3 Counts of ST = 4
Any clue how to solve this?
while (#array) will be an infinite loop since #array never gets smaller. You can't read into the default variable $_ this way. For this to work, use for (#array) which will read the array items into $_ one at a time until all have been read.
The tr transliteration operator is the right tool for your task.
The code needed to get your results could be:
#!/usr/bin/perl
use strict;
use warnings;
my #data = ("QQQRRRRSCCTTTS", "ZZZSTTKQSST", "ZBQLDKSSSS");
my $i = 1;
for (#data) {
my $count = tr/ST//;
print "Element $i Counts of ST = $count\n";
$i++;
}
Also, note that my $count = tr/ST//; doesn't require the binding of the transliteration operator with $_. Perl assumes this when $_ holds the value to be counted here. Your code tried my $s = ($_ = tr/S//); which will give the results but the shorter way I've shown is the preferred way.
(Just noticed you had = instead of =~ in your statement. That is an error. Has to be $s = ($_ =~ tr/S//);)
You can combine the 2 sought letters as in my code. Its not necessary to do them separately.
I got the output you want.
Element 1 Counts of ST = 5
Element 2 Counts of ST = 6
Element 3 Counts of ST = 4
Also, you can't perform math operations in a quoted string like you had.
print "ST are in total $s + $t\n";
Instead, you would need to do:
print "ST are in total ", $s + $t, "\n";
where the operation is performed outside of the string.
Don't use while to traverse an array - your array gets no smaller, so the condition is always true and you get an infinite loop. You should use for (or foreach) instead.
for (#array) {
my $s = tr/S//; # No need for =~ as tr/// works on $_ by default
my $t = tr/T//;
print "ST are in total $s + $t\n";
}
Why tr///??
sub main {
my #array = #_;
while (#array) {
my $s = split(/S/, $_, -1) - 1;
my $t = split(/T/, $_, -1) - 1;
print "ST are in total $s + $t\n";
}
}
I'm trying to understand the 'Common Mistake' section in the perldsc documentation. What is the author trying to convey when he mentions:
The two most common mistakes made in constructing something like an array of arrays is either accidentally counting the number of elements or else taking a reference to the same memory location repeatedly. Here's the case where you just get the count instead of a nested array:
for my $i (1..10) {
my #array = somefunc($i);
$AoA[$i] = #array; # WRONG!
}
From what I understand is that when it iterate it will take the first value of (1..10) which is 1 and will pass it to a function like this:
my #array = somefunc(1);
Since that function is not defined, I'll create the logic.
sub somefunc {
my $a = shift;
print $a * $a;
}
which will essentially do this:
1 * 1
and the result is '1'.
To my understanding my #array will look like:
#array = ('1');
And the next line will do:
$AoA[$i] = #array;
I'm assuming that $AoA[$1] is an anonymous array ( he/she didn't declare with 'my', btw) and the #array will be the first element of the this anonymous array which the author said it' WRONG. And the for each loop with iterate to '2'.
somefunc(2);
Which will be '4' and passed to:
$AoA[$i] = #array
What is the point of the author with this code which is wrong. I'm trying to understand what is wrong but more importantly, I'm trying to understand the code. Any help will be appreciated.
UPDATE
I think I understand why this is a common mistake because when I use print and Dumper, I can visually see what the author is trying to convey, here is the revised code.
#!/usr/bin/perl -w
use strict;
use Data::Dumper;
for my $i (1..10) {
my #AoA;
my #array = somefunc($i);
print "The array is Dumper(#array)\n";
$AoA[$i] = #array; # WRONG!
print Dumper($AoA[$i]);
}
sub somefunc {
my $a = shift;
return $a * $a;
}
In the Common Mistakes paragraph of perldoc perldsc, he/she states
Here's the case where you just get the count instead of a nested array:
Below is the output of the Dumper.
The array is Dumper(1)
$VAR1 = 1;
The array is Dumper(4)
$VAR1 = 1;
The array is Dumper(9)
$VAR1 = 1;
The array is Dumper(16)
$VAR1 = 1;
The array is Dumper(25)
$VAR1 = 1;
The array is Dumper(36)
$VAR1 = 1;
The array is Dumper(49)
$VAR1 = 1;
The array is Dumper(64)
$VAR1 = 1;
The array is Dumper(81)
$VAR1 = 1;
The array is Dumper(100)
$VAR1 = 1;
So I'm assuming that the repeated
$VAR1 = 1;
is the count and not the nested array.
The author did indicate that if the count is what I truly want then to rewrite the code like this:
#!/usr/bin/perl -w
use strict;
use Data::Dumper;
for my $i (1..10) {
my #count;
my #array = somefunc($i);
print "The array is Dumper(#array)\n";
$count[$i] = scalar #array;
print Dumper($count[$i]);
}
sub somefunc {
my $a = shift;
return $a * $a;
}
But the documentation didn't tell me how to get the nested array?
UPDATE
Correct me if I am wrong but I rewrote the code to get the nested array:
#!/usr/bin/perl -w
use strict;
use Data::Dumper;
my #count;
my #new_array;
for my $i (1..10) {
#my #count;
my #array = somefunc($i);
push #new_array, [#array];
}
sub somefunc {
my $a = shift;
return $a * $a;
}
print Dumper(\#new_array);
Which printed
$VAR1 = [
[
1
],
[
4
],
[
9
],
[
16
],
[
25
],
[
36
],
[
49
],
[
64
],
[
81
],
[
100
]
];
In the following statement:
$AoA[$i] = #array;
the #array is referenced in a scalar context, yielding a number of its elements. The context is imposed by LHS, that is $AoA[$i] which is a single element of the #AoA array.
In Perl, there are no array of arrays in a strict sense. These are emulated essentially by either "flatten" arrays or array with references. For the latter, you would need to use take reference operator as in:
$AoA[$i] = \#array;
For the starter, you may find, that Data::Dumper is very handy in examining complex data stuctures such as arrayrefs and hashrefs.
Perl is polymorphic, which means that it deals with different data types transparently, and makes what is usually a pretty good guess on how to deal with something. This makes the programmer's work much easier because it is not strongly typed like other languages.
So for example if $i is the number 4, you can do this:
print $i + 1;
and you will see a 5 - pretty logical, right?
and if you do this:
print "I am " , $i , " years old";
You will see "I am 4 years old" - in this case perl says "you are operating in list context, so I will treat $i as a string. No need to convert the number into a string as many other languages insist.
So when you assign
$AoA[$i] = #array;
The way it treats this depends on the context. In scalar context, it will set $AoA[$i] to be the length of the array.
For more information about scalar vs list context, read this answer:
http://perl.plover.com/context.html
Your example isn't very useful in understanding what is going on here as your subroutine always returns "1" - the result of calling print(). If you replace the print() with return() then you will at get different values (1, 4, 9, etc).
But the next line of code:
$AoA[$i] = #array;
Will always assign 1 to the element of #Aoa. That's because You are assigning an array (#array) to a scalar variable ($AoA[$i]) and when you evaluate an array in a scalar context, you get the number of elements in the array.
Now, as your #array only ever has a single element, you could do this:
$AoA[$i] = $array[0];
But that's not really building an array of arrays. What you really want to do is to get a reference to an array.
$AoA[$i] = \#array;
This would be more useful if your subroutine returned more than one value.
sub somefunc {
# Used $x instead of $a as $a has a special meaning in Perl
my $x = shift;
return ($x * $x, $x * $x * $x);
}
for my $i (1..10) {
my #array = somefunc($i);
$AoA[$i] = \#array;
}
As useful tool for exploring this is Data::Dumper. Try adding:
use Data::Dumper;
To the top of your code and:
print Dumper #AoA;
After the foreach loop to see the different data structures that you get back.
Is map function in Perl written in Perl? I just can not figure out how to implement it. Here is my attempt:
use Data::Dumper;
sub Map {
my ($function, $sequence) = #_;
my #result;
foreach my $item (#$sequence) {
my $_ = $item;
push #result, $function->($item);
}
return #result
}
my #sample = qw(1 2 3 4 5);
print Dumper Map(sub { $_ * $_ }, \#sample);
print Dumper map({ $_ * $_ } #sample);
$_ in $function is undefined as it should be, but how map overcomes this?
map has some special syntax, so you can't entirely implement it in pure-perl, but this would come pretty close to it (as long as you're using the block form of map):
sub Map(&#) {
my ($function, #sequence) = #_;
my #result;
foreach my $item (#sequence) {
local $_ = $item;
push #result, $function->($item);
}
return #result
}
use Data::Dumper;
my #sample = qw(1 2 3 4 5);
print Dumper Map { $_ * $_ } #sample;
print Dumper map { $_ * $_ } #sample;
$_ being undefined is overcome by using local $_ instead of my $_. Actually you almost never want to use my $_ (even though you do want to use it on almost all other variables).
Adding the (&#) prototype allows you not to specify sub in front of the block. Again, you almost never want to use prototypes but this is a valid use of them.
While the accepted answer implements a map-like function, it does NOT do it in the way perl would. An important part of for, foreach, map, and grep is that the $_ they provide to you is always an alias to the values in the argument list. This means that calling something like s/a/b/ in any of those constructs will modify the elements they were called with. This allows you to write things like:
my ($x, $y) = qw(foo bar);
$_ .= '!' for $x, $y;
say "$x $y"; # foo! bar!
map {s/$/!!!/} $x, $y;
say "$x $y"; # foo!!!! bar!!!!
Since in your question, you have asked for Map to use array references rather than arrays, here is a version that works on array refs that is as close to the builtin map as you can get in pure Perl.
use 5.010;
use warnings;
use strict;
sub Map (&\#) {
my ($code, $array) = splice #_;
my #return;
push #return, &$code for #$array;
#return
}
my #sample = qw(1 2 3 4 5);
say join ', ' => Map { $_ * $_ } #sample; # 1, 4, 9, 16, 25
say join ', ' => map { $_ * $_ } #sample; # 1, 4, 9, 16, 25
In Map, the (&\#) prototype tells perl that the Map bareword will be parsed with different rules than a usual subroutine. The & indicates that the first argument will either be a bare block Map {...} NEXT or it will be a literal code reference Map \&somesub, NEXT. Note the comma between the arguments in the latter version. The \# prototype indicates that the next argument will start with # and will be passed in as an array reference.
Finally, the splice #_ line empties #_ rather than just copying the values out. This is so that the &$code line will see an empty #_ rather than the args Map received. The reason for &$code is that it is the fastest way to call a subroutine, and is as close to the multicall calling style that map uses as you can get without using C. This calling style is perfectly suited for this usage, since the argument to the block is in $_, which does not require any stack manipulation.
In the code above, I cheat a little bit and let for do the work of localizing $_. This is good for performance, but to see how it works, here is that line rewritten:
for my $i (0 .. $#$array) { # for each index
local *_ = \$$array[$i]; # install alias into $_
push #return, &$code;
}
My Object::Iterate module is an example of what you are trying to do.
I know that passing a scalar to a sub is actually passing the reference, but since I am new to perl I still did the following test:
#!/usr/bin/perl
$i = 2;
subr(\$i);
sub subr{
print $_[0]."\n";
print $$_[0]."\n";
}
I thought the first line is going to print an address and the second line is going to give be back the number, but the second one is a blank line. I was pointed by someone one else to do this: ${$_[0]} and it prints the number. But she didn't know the reason why without {} it is not working and why it is working with {}. So what has happened?
It's because your second print statement is equivalent to doing this...
my $x = $$_; print $x[0];
When what you want is
my $x = $_[0]; print $$x;
In other words, the de-referencing occurs before the array subscript is evaluated.
When you add those curl-wurlies, it tells perl how to interpret the expression as you want it; it will evaluate $_[0] first, and then de-reference to get the value.
It's an order-of-evaluation thing.
$$_[0] is evaluated as {$$_}[0]
This is the 0th element of the reference of the scalar variable $_. It's taking the reference first and then trying to find the 0th element of it.
${$_[0]}
This is a reference to the 0th element of the array #_. It's finding the 0th element first then taking a reference of that.
If you set use strict and use warnings at the top of your code you'll see plenty of warnings about undefined values from your first attempt.
$$_[0] is like $foo[0], only with $_ in place of the array name. This means $_ is treated as an array reference, and the expression doesn't involve the scalar reference $_[0] at all. $_->[0] is equivalent, using the alternate -> syntax. Syntax for dereferencing may seem arbitrary and hard to remember, but there is underlying sense and order; a very good presentation of it is at http://perlmonks.org/?node=References+quick+reference.
You don't have to pass a reference to $i. The notation $_[0] is an alias for $i when you invoke it as subr( $i ).
use strict;
use warnings;
use Test::More tests => 2;
sub subr{ $_[0]++ } # messing with exactly what was passed first
my $i=2;
is( $i, 2, q[$i == 2] );
subr($i);
is( $i, 3, q[$i == 3] );
Another example is this:
use strict;
use warnings;
use Test::More tests => 6;
use Test::Exception;
sub subr{ $_[0]++ }
my $i=2;
is( $i, 2, q[$i == 2] );
subr($i);
is( $i, 3, q[$i == 3] );
sub subr2 { $_[0] .= 'x'; }
dies_ok { subr2( 'lit' ); } 'subr2 *dies* trying to modify a literal';
lives_ok {
my $s = 'lit';
subr2( $s );
is( $s, 'litx', q[$s eq 'litx'] );
subr2(( my $s2 = 'lit' ));
is( $s2, 'litx', q[$s2 eq 'litx'] );
} 'subr2 lives with heap variables';
Output:
ok 1 - $i == 2
ok 2 - $i == 3
ok 3 - subr2 *dies* trying to modify a literal
ok 4 - $s eq 'litx'
ok 5 - $s2 eq 'litx'
ok 6 - subr2 lives with heap variables
1..6