I'm trying to generate arrays for each of the agregations of cells in suduko. I seem to have fixed the problem, but don't understand what my earlier alternatives are doing.
I get the answer I expected if I write for instance:
#row = ( [], [], [], [], [], [], [], [], [] ) ;
I had expected
#row = ( [] ) x 9 ;
to behave the same. I also tried, which did better
#row = ( [] x 9 ) ;
Only the first element comes out strange with this, in two of the arrays. With the first rejected form I get all 81 elements in each array
I did wonder if the last form was actually legal?
# prob.pl - Show problem with repeat anonymous arrays
#
# ###################################################
#row = ( [] x 9 ) ;
#col = ( [] x 9 ) ;
#box = ( [] x 9 ) ;
for ( $i = 0 ; $i < 81 ; $i ++ ) {
push( #{$row[ row($i) ]}, $i ) ;
push( #{$col[ col($i) ]}, $i ) ;
push( #{$box[ box($i) ]}, $i ) ;
}
for ( $i = 0 ; $i < 9 ; $i ++ ) {
print STDERR "\#{\$row[$i]} = #{$row[$i]}\n" ;
print STDERR "\#{\$col[$i]} = #{$col[$i]}\n" ;
print STDERR "\#{\$box[$i]} = #{$box[$i]}\n" ;
}
sub row {
my( $i ) = #_ ;
int( $i / 9 ) ;
}
sub col {
my( $i ) = #_ ;
$i % 9 ;
}
sub box {
my( $i ) = #_ ;
int( col( $i ) / 3 ) + 3 * int( row( $i ) / 3 ) ;
}
Answer in two parts: first part is a simple view of what is happening and what you should do to fix it. Second part tries to explain this weird behavior you're getting.
Part 1 - simple explanations
All forms are legal; they are just not equivalent and probably don't do what you expect. In such case, Data::Dumper or Data::Printer are your friends:
use Data::Printer;
my #a1 = ( [] x 9 );
p #1;
Prints something like
[
[0] "ARRAY(0x1151f30)ARRAY(0x1151f30)ARRAY(0x1151f30)ARRAY(0x1151f30)ARRAY(0x1151f30)ARRAY(0x1151f30)ARRAY(0x1151f30)ARRAY(0x1151f30)ARRAY(0x1151f30)"
]
Quoting the doc of x (the "repetition operator", if you need to search for it):
In scalar context, or if the left operand is neither enclosed in parentheses nor a qw// list, it performs a string repetition.
([] x 9 calls x in scalar context)
On the other hand, when you do ([]) x 9, you get something like:
[
[0] [],
[1] var[0],
[2] var[0],
[3] var[0],
[4] var[0],
[5] var[0],
[6] var[0],
[7] var[0],
[8] var[0]
]
Quoting the doc again:
If the x is in list context, and the left operand is either enclosed in parentheses or a qw// list, it performs a list repetition. In that case it supplies list context to the left operand, and returns a list consisting of the left operand list repeated the number of times specified by the right operand.
What happens here, is that [] is evaluated before x is applied. It creates an arrayref, and x 9 then duplicates it 9 times.
Correct ways to achieve what you want would be either your first solution, or maybe, if you prefer something more concise (but still readable):
my #row = map { [] } 1 .. 9;
(since the body of the map is evaluated at each iteration, it creates indeed 9 distinct references)
Or, you could just not initialize #row, #col and #box and let autovivification creates the arrays when needed.
Part 2 - advanced explanation
You have some weird behavior with your program when you use ([] x 9). For simplicity, let me reproduce it with a simpler example:
use feature 'say';
#x = ([] x 5);
#y = ([] x 5);
#z = ([] x 5);
push #{$x[0]}, 1;
push #{$y[0]}, 1;
push #{$z[0]}, 1;
say "#{$x[0]}";
say "#{$y[0]}";
say "#{$z[0]}";
This program outputs:
1 1
1
1 1
Interestingly, removing the definition of #y (#y = ([] x 5)) from this programs produces the output:
1
1
1
Something fishy is going on. I'll explain it with two points.
First, let's consider the following example:
use Data::Printer;
use feature 'say';
say "Before:";
#x = "abcd";
p #x;
say "#{$x[0]}";
say "After:";
push #{$x[0]}, 5;
p #x;
say "#{$x[0]}";
say $abcd[0];
Which outputs
Before:
[
[0] "abcd"
]
After:
[
[0] "abcd"
]
5
5
When we do push #{$x[0]}, 5, #{$x[0]} becomes #{"abcd"}, which creates the arrays #abcd, and pushes 5 into it. $x[0] is still a string (abcd), but this string is also the name of an array.
Second*, let's look at the following program:
use Data::Printer;
#x = ([] x 5);
#y = ([] x 5);
#z = ([] x 5);
p #x;
p #y;
p #z;
We get the output:
[
[0] "ARRAY(0x19aff30)ARRAY(0x19aff30)ARRAY(0x19aff30)ARRAY(0x19aff30)ARRAY(0x19aff30)"
]
[
[0] "ARRAY(0x19b0188)ARRAY(0x19b0188)ARRAY(0x19b0188)ARRAY(0x19b0188)ARRAY(0x19b0188)"
]
[
[0] "ARRAY(0x19aff30)ARRAY(0x19aff30)ARRAY(0x19aff30)ARRAY(0x19aff30)ARRAY(0x19aff30)"
]
#x and #z contain the same reference. While this is surprising, I think that this is explainable: line 1, [] x 5 creates an arrayref, then converts it into a string to do x 5, and then it doesn't use the arrayref anymore. This means that the garbage collector is free to reclaim its memory, and Perl is free to reallocate something else at this address. For some reason, this doesn't happen right away (#y doesn't contain the same thing as #x), but only when allocating #z. This is probably just the result of the implementation of the garbage collector / optimizer, and I suspect it might change from a version to another.
In the end, what happens is this: #x and #z contains a single element, a string, which is identical. When you dereference $x[0] and $z[0], you therefore get the same array. Therefore, pushing into either $x[0] or $z[0] pushes into the same array.
This would have been caught with use strict, which would have said something like:
Can't use string ("ARRAY(0x2339f30)ARRAY(0x2339f30)"...) as an ARRAY ref while "strict refs" in use at repl1.pl line 11.
* note that for this second part, I am not sure that this is what happens, and this is only my (somewhat educated) guess. Please, don't take my word for it, and feel free to correct me if you know better.
The second form creates 9 copies of the same array reference. The third form creates a single array element consisting of a string like "ARRAY(0x221f488)" concatenated together 9 times. Either create 9 individual arrays with e.g. push #row, [] for 1..9; or rely on autovivification.
Related
I try to make a grep like on a PDL matrix or array of Vector :
my #toto;
push(#toto, pdl(1,2,3));
push(#toto, pdl(4,5,6));
my $titi=pdl(1,2,3);
print("OK") if (grep { $_ eq $titi} #toto);
I also tried
my #toto;
push(#toto, pdl(1,2,3));
push(#toto, pdl(4,5,6));
my $titi=pdl(1,2,3);
print("OK") if (grep { $_ eq $titi} PDL::Matrix->pdl(\#toto));
None works.
Any help Please
Disclaimer: I don't know anything about PDL. I've read the source to figure this one out.
There's a function PDL::all() that you can use in conjunction with the overloaded comparison operator ==.
use PDL;
my $foo = pdl(1,2,3);
my $bar = pdl(4,5,6);
my $qrr = pdl(1,2,3);
print "OK 1" if PDL::all( $foo == $bar );
print "OK 2" if PDL::all( $foo == $qrr );
I'm still looking for the documentation.
The way to do this efficiently, in a way that scales, is to use PDL::VectorValued::Utils, with two ndarrays (the "haystack" being an ndarray, not a Perl array of ndarrays). The little function vv_in is not shown copy-pasted into the perldl CLI because it would be less copy-pastable from this answer:
sub vv_in {
require PDL::VectorValued::Utils;
my ($needle, $haystack) = #_;
die "needle must have 1 dim less than haystack"
if $needle->ndims != $haystack->ndims - 1;
my $ign = $needle->dummy(1)->zeroes;
PDL::_vv_intersect_int($needle->dummy(1), $haystack, $ign, my $nc=PDL->null);
$nc;
}
pdl> p $titi = pdl(1,2,3)
[1 2 3]
pdl> p $toto = pdl([1,2,3], [4,5,6])
[
[1 2 3]
[4 5 6]
]
pdl> p $notin = pdl(7,8,9)
[7 8 9]
pdl> p vv_in($titi, $toto)
[1]
pdl> p vv_in($notin, $toto)
[0]
Note that for efficiency, the $haystack is required to be sorted already (use qsortvec). The dummy "inflates" the $needle to be a vector-set with one vector, then vv_intersect returns two ndarrays:
either the intersecting vector-set (which would always be a single vector here), or a set of zeroes (probably a shortcoming of the routine, it should instead be vectorlength,0 - an empty ndarray)
the quantity of vectors found (here, either 0 or 1)
The "internal" (_vv_intersect_int) version is used because as of PDL::VectorValued 1.0.15, it has some wrapping Perl code that does not permit broadcasting (an issue has been filed).
Note vv_in will "broadcast" (formerly known, confusingly, as "threading") over multiple sets of input-vectors and input-haystacks. This could be used to search for several vectors:
sub vv_in_multi {
my ($needles, $haystack) = #_;
die "needles must have same number of dims as haystack"
if $needles->ndims != $haystack->ndims;
vv_in($needles, $haystack->dummy(-1));
}
pdl> p vv_in_multi(pdl($titi,$notin), $toto)
[1 0]
Thanks to Ed for the VectorValued shout-out above (and for the bug report too). On reflection, it occurs to me that if $toto is sorted (a la qsortvec(), as it is in your example), you can get away with using vsearchvec(), also from PDL::VectorValued::Utils and typically faster than vv_intersect (logarithmic vs. linear):
sub vv_in_vsearch {
require PDL::VectorValued::Utils;
my ($needle, $haystack) = #_;
my $found = $needle->vsearchvec($haystack);
return all($haystack->dice_axis(1,$found) == $needle);
}
pdl> $titi = pdl(1,2,3)
pdl> $tata = pdl(4,5,6)
pdl> $toto = pdl([1,2,3], [4,5,6])
pdl> $notin = pdl(7,8,9)
pdl> p vv_in_vsearch($titi, $toto)
1
pdl> p vv_in_vsearch($tata, $toto)
1
pdl> p vv_in_vsearch($notin, $toto)
0
(full disclosure: I wrote & maintain PDL::VectorValued)
You can use eq_pdl from Test::PDL:
use PDL;
use Test::PDL qw( eq_pdl );
my #toto;
push(#toto, pdl(1,2,3));
push(#toto, pdl(4,5,6));
my $titi = pdl(4,5,6);
print("OK\n") if (grep { eq_pdl( $_, $titi) } #toto);
Output:
OK
I have the following Perl code.
#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;
my #array = ( 3, 4, 1, 4, 7, 7, 4, 1, 3, 8 );
my %unordered;
#unordered{#array} = undef;
foreach my $key (keys %unordered) {
print "Unordered: $key\n";
}
my %seen;
my #ordered;
foreach my $element (#array) {
if ( not $seen{$element}++ ) {
push #ordered, $element;
}
}
In the last foreach code block, I am unable to understand this - in the first iteration, the expression not $seen{$element}++ evaluate to not 0 - true - so the if block execute. In the second iteration the expression not $seen{$element}++ should again evaluate to not 0 - true as the hash is empty. So, reading the scalar $seen{$element} will read 0 and not 0 will evaluate to true. So, the if block should execute again. But, the book says it stops after first iteration. Can anyone explain this?
In the second iteration the hash will no longer be empty, because the ++ operator will have put a 1 in there. In a third iteration the value will be 2 (which for the purposes of this program is the same as 1, it just means "seen at least once before").
At the end of your program %seen will contain the number of times each entry appears in your list.
if $a++ increments the value of $a (treating it as 0 if missing), and then returns the value before that increment to the comparison.
It is important to use the postfix operator, as if ++$a will not work here: It also places a 1 in your hash, but it returns the modified value (so 1 even for the first iteration).
The last foreach loop can be detailled as:
# loop on all elements of the array
foreach my $element (#array) {
# if the current element haven't been seen yet
if ( not exists $seen{$element} ) {
# add current element into ordered array
push #ordered, $element;
}
# Increment the number of time element have been seen
$seen{$element}++;
}
At the end, #ordered will contain:
(3, 4, 1, 7, 8)
A better name should be #unique instead of #ordered.
%seen will contain:
(3 => 2, 4 => 3, 1 => 2, 7 => 2, 8 => 1)
I want to create 10 one dimensional arrays , and put these 10 one dimensional arrays to another one dimensional array , and store some data to some specific index of array .
but the output what I expect should be
expect output real output
0 1
1 1
0 1
3 1
0 1
5 1
0 1
7 1
0 1
0 1
here is my code
#Hits = ();
# Create 10 one dimension array
for($i=0;$i<=9;$i++)
{
#Space = ();
push(#Hits,\#Space);
}
# Store some data to some index
push(#{$Hits[1]},1);
push(#{$Hits[3]},3);
push(#{$Hits[5]},5);
push(#{$Hits[7]},7);
# print the first element of 10 arrays
for($i=0;$i<=9;$i++)
{
print $Hits[$i]->[0];
print "\n";
}
thanks
The Problem is that you aren't properly declaring your variables. For every script, you should
use strict; use warnings;
This disallows common error sources, warns about iffy stuff, and forces you to properly declare all your variables.
By default, all undeclared variables are considered global. Therefore, in
for($i=0;$i<=9;$i++)
{
#Space = ();
push(#Hits,\#Space);
}
the #Space refers to the same array in each iteration. Ergo, all ten entries in #Hits are a reference to the same array. Let's inspect what #Hits actually is. We can do so with Data::Dumper or the Data::Dump module (the latter usually produces prettier output):
use Data::Dump; # use Data::Dumper;
dd \#Hits; # print Dumper \#Hits;
We get with Data::Dumper (easier to understand):
$VAR1 = [
[
1,
3,
5,
7
],
$VAR1->[0],
$VAR1->[0],
$VAR1->[0],
$VAR1->[0],
$VAR1->[0],
$VAR1->[0],
$VAR1->[0],
$VAR1->[0],
$VAR1->[0]
];
So I said the solution would be declaring your variables. Specifically, we want lexical variables. These variables are only visible inside the block where they are declared. This makes reasoning about code much easier. We can declare a lexical variable like so:
my $foo = 123;
When we have a loop like
my #Hits;
for my $i (0 .. 9) {
my #Space;
push #Hits, \#Space;
}
then each time the my is executed, we get a new #Space. Oh, and I have used a foreach-loop, that iterates over the range 0 .. 9 with the (lexical) $i variable. I find this easier to understand than the C-style loops you used.
Because every element in #Hits now is a different arrayref, we get the expected data structure. As Data::Dump output:
[[], [1], [], [3], [], [5], [], [7], [], []]
When we now execute your loop that prints out the first value of each sub-array, then you may be suprised by the empty lines in between the numebers. This is because e.g. the first arrayref does not have an entry at index 0, and therefore returns the special undef value. When used as a string, this is the empty string. If you followed my advice and did the use warnings, you also get a message that you are printing an uninitialized value.
We can solve this by testing for definedness, and providing a zero otherwise. Since perl5 v10, we can use the defined-or operator // for this (on earlier perls, the || logical or has to do).
for my $i (0 .. 9) {
my $value = $Hits[$i][0] // 0;
print "$value\n";
}
There are a few other bits we can improve:
We don't have to manually create the #Space arrays; Perl does this behind the scenes when you dereference an array entry like #{ $Hits[$i] }. This is called autovivification.
Not only can we iterate over ranges, but also over arrays. This is much better than hardcoding indices.
Since v10, you can use the say feature. The say function is exactly like print but appends a newline at the end.
Here is how I'd have written that code:
#!/usr/bin/perl
use strict; use warnings; use feature 'say';
my #Hits;
for my $i (1, 3, 5, 7) {
push #{ $Hits[$i] }, $i;
}
for my $arrayref (#Hits) {
say $arrayref->[0] // 0;
}
Output:
0
1
0
3
0
5
0
7
(Note that we never initialized values at positions 8 and 9, so they are not shown. We could amend this by iterating over the slice #Hits[0 .. 9].)
I change your code like following:
#! /usr/bin/perl -w
#Hits = ();
push(#{$Hits[1]},1);
push(#{$Hits[3]},3);
push(#{$Hits[5]},5);
push(#{$Hits[7]},7);
#print the content of
for($i=0;$i<=9;$i++)
{
if (defined ($Hits[$i])) {
print "$Hits[$i][0]\n";
} else {
print "0\n";
}
}
It's incorrect to give the ref of #space to #Hits and that makes the wrong result. It's not necessary to initial #Hits in perl.
perl -e "use Data::Dump; #sf=(); push #{$sf[0]},"0"; push #{$sf[1]},"1"; dd \#sf;"
[[0], [1]]
or
perl -e "use Data::Dump; #sf=(); push #sf,["0"]; push #sf,["1"]; dd \#sf;"
[[0], [1]]
I have a text file with numbers which I have grouped as follows, seperated by blank line:
42.034 41.630 40.158 26.823 26.366 25.289 23.949
34.712 35.133 35.185 35.577 28.463 28.412 30.831
33.490 33.839 32.059 32.072 33.425 33.349 34.709
12.596 13.332 12.810 13.329 13.329 13.569 11.418
Note: the groups are always of equal length and can be arranged in more than one line long, if the group is large, say 500 numbers long.
I was thinking of putting the groups in arrays and iterate along the length of the file.
My first question is: how should I subtract the first element of array 2 from array 1, array 3 from array 2, similarly for the second element and so on till the end of the group?
i.e.:
34.712-42.034,35.133-41.630,35.185-40.158 ...till the end of each group
33.490-34.712,33.839-35.133 ..................
and then save the differences of the first element in one group (second question: how ?) till the end
i.e.:
34.712-42.034 ; 33.490-34.712 ; and so on in one group
35.133-41.630 ; 33.839-35.133 ; ........
I am a beginner so any suggestions would be helpful.
Assuming you have your file opened, the following is a quick sketch
use List::MoreUtils qw<pairwise>;
...
my #list1 = split ' ', <$file_handle>;
my #list2 = split ' ', <$file_handle>;
my #diff = pairwise { $a - $b } #list1, #list2;
pairwise is the simplest way.
Otherwise there is the old standby:
# construct a list using each index in #list1 ( 0..$#list1 )
# consisting of the difference at each slot.
my #diff = map { $list1[$_] - $list2[$_] } 0..$#list1;
Here's the rest of the infrastructure to make Axeman's code work:
#!/usr/bin/perl
use strict;
use warnings;
use List::MoreUtils qw<pairwise>;
my (#prev_line, #this_line, #diff);
while (<>) {
next if /^\s+$/; # skip leading blank lines, if any
#prev_line = split;
last;
}
# get the rest of the lines, calculating and printing the difference,
# then saving this line's values in the previous line's values for the next
# set of differences
while (<>) {
next if /^\s+$/; # skip embedded blank lines
#this_line = split;
#diff = pairwise { $a - $b } #this_line, #prev_line;
print join(" ; ", #diff), "\n\n";
#prev_line = #this_line;
}
So given the input:
1 1 1
3 2 1
2 2 2
You'll get:
2 ; 1 ; 0
-1 ; 0 ; 1
In a previous question, seaworthy asked how to remove the first 5 elements from an array:
How do I remove the first five elements of an array?
Among several suggestions, friedo offered this:
my $cnt = 0;
#array = map { ++$cnt < 5 ? ( ) : $_ } #array;
I don't get the ( ) bit. Please could explain how this works to me, because I can't get my head around it?
I know that the ternary hook operator works like this:
(if something) ? (then do this) : (otherwise do this)
For example: $a=2; print ($a==2 ? 3 : 4) # this prints: 3
because we have: ($a==2 ? 3 : 4)
which means: (if $a is equal to 2) ? (then print 3) : (otherwise print 4)
so with friedo's code, first $cnt is increased to 1, then we have:
$cnt < 5 ? ( ) : $_
which means:
if $cnt is less than 5 ? then ( ) : otherwise $_
I can see how the $_ bit works because i sometimes use map like this:
#array = map { $_, "\n" } #array
This copies an element from #array, places the copy into $, then adds a \n newline, then it copies the value in $ back to #array (and it does this with all values in #array so basically it adds newlines to every element in #array)
therefore:
#array = map { if $cnt is less than 5 then ( ) otherwise $_ } #array
means something like:
#array = map { if $cnt is less than 5 then ( ) otherwise copy the element back to #array }
so clearly ( ) means something like 'get rid of it'
but i'm just not sure how it works. Please could you explain it?
In a map, each item from the array is passed into the code block (in $_) where it can be transformed into some other value. In other words, map transforms a list.
In this case, we want to throw away values where the count ($cnt) is less than 5. So how to we make a map block return "nothing" when that condition is true?
We can't say
my $cnt = 0; #array = map { ++$cnt < 5 ? undef : $_ } #array;
Because then we'd end up with an array that looks like
( undef, undef, undef, undef, undef, 6, 7, 8 ... )
which is not what we wanted.
But returning ( ) instead returns an empty list. Consider push #foo, ( ); or #bar = ( 1, 2, 3, ( ), 4, 5, 6 ); In each of these cases, the empty set of parens is a list of zero items, which doesn't have any affect on the arrays concerned.
The empty list is useful in ternaries where you need to either return a list item or nothing at all. It's also useful to force list context on an expression to get a count:
my $count = ( ) = $str =~ /\d/g;
Here, we put the regex in list context by assigning it to an empty list, giving us the count of digits in the string. Then we assign that empty list to $count.
Another frequent example of using lists in map is when you're transforming something into a hash. For example,
my %unique = map { $_ => 1 } #duplicates;
Here each single item in #duplicates get transformed into a two-element list that looks like ( 'foo' => 1 ) although it's not as obvious since no parens are involved. All the two-item lists then get built up into one big list of alternating keys and values which construct the hash. Let's say you wanted to make this hash but exclude some items. In this case we either need to return a key/value, or nothing. So that's a good chance to use an empty list:
my %filtered_unique = map { some_test( $_ ) ? ( ) : ( $_ => 1 ) } #duplicates;
I know I'm a bit late in the game here, but why not do something simple?
my #truncated = #array[5 .. $#array]
Apparantly you can return a list instead of an element, and map constructs the result by joining those lists and elements. () is just the empty list in this case. For more insight, copy-paste the example, and replace () by (1, 2, 3).