Defining 2D array inside class of Perl - arrays

I am new to Perl and I am trying to define a 2D array as an attribute of my class in Perl. I define my class as follows,
sub new{
my $class = shift;
my $self = {};
my #board = [];
for (my $i = 0; $i < 8; $i++){
for(my $j = 0; $j < 8; $j++){
$board[$i][$j] = '.';
}
}
$self->{board} = #board;
bless($self, $class);
return $self;
}
But later on when I try to access the board field like this
$self->{board}[$i][$j] = ' ';
I got an error saying
Can't use string ("8") as an ARRAY ref while "strict refs" in use
Can anyone tell me what is the correct way of doing this? I do not want to just delete use strict.

I changed your code to what I'm sure was your intention,
see the lines changed and comment # not
sub new{
my $class = shift;
my $self = {};
my #board = (); # not []
for (my $i = 0; $i < 8; $i++){
for(my $j = 0; $j < 8; $j++){
$board[$i][$j] = '.';
}
}
$self->{board} = \#board; # not #board
bless($self, $class);
return $self;
}
or
sub new{
my $class = shift;
my $self = {};
my $board = []; # not #board
for (my $i = 0; $i < 8; $i++){
for(my $j = 0; $j < 8; $j++){
$board->[$i][$j] = '.';
}
}
$self->{board} = $board; # not #board
bless($self, $class);
return $self;
}
about your my #board=[]; is the same as =([],); assign a list (that perl calls ARRAY) whose first element is a reference to an ARRAY to #board, but this is neither what make your code fail because you overwrite this empty array reference allocation and assignment to position zero.
The #board is a list not a reference to it as $self->{board} expect

You need to place a reference to array inside your $self hash. Right now you're placing a value of array in scalar context - which is its length 8. Of course you can't later use this as a reference to anything.
$self->{board} = \#board;

Others have given you explanations of what the problem is with your constructor. I'll add, that you can simplify it a bit by omitting the $board variable and using C-style loops.
sub new {
my $class = shift;
my $self = {};
$self->{board} = [];
for my $i (1 .. 8) {
for my $j (1 .. 8) {
$self->{board}[$i][$j] = '.';
}
}
return bless $self, $class;
}
I'd also add the following three methods which make it easier to set and get the elements of the board:
sub board {
my $self = shift;
return $self->{board};
}
sub set_board_element {
my $self = shift;
my ($i, $j, $val) = #_;
$self->board->[$i][$j] = $val;
}
sub get_board_element {
my $self = shift;
my ($i, $j) = #_;
return $self->board->[$i][$j];
}
Have you considered using Moose to write your class? It will make your life easier. In particular, Array traits seem like a good fit for your problem.

Related

How to map 2 arrays of object using PowerShell?

I would like to map an array object. I need to find the matched object of array. After the object match, I need to stop checking other objects, then continue to the next process.
I tried this, but it always return not match, even if the array object match exists.
$ID = #("8537", "8538", "8539", "8540", "85AC", "85DE", "82EA")
$Signal = #("8537", "8220")
for ($i = 0; $i -lt $Signal.count; $i++)
{
if ($Signal[$i] -like "$ID[$i]")
{
"found ‘$($Signal[$i])’
at index $i"
# Do some process
}
else {
"Not Match"
# Do some process
}
}
If you need to go Match process if exists at least 1 match object, you can try this:
$ID = #("8538", "8539", "8540", "85AC", "85DE", "82EA","8537")
$Signal = #("8537","8220","85DE")
$matched = $false
for ($i = 0; $i -lt $ID.count; $i++) {
if ($matched) {
break
}
for ($j = 0; $j -lt $Signal.count; $j++) {
if ($ID[$i] -like $Signal[$j])
{
$matched = $true
"found $($ID[$i]) at index $i"
break
}
}
}
if ($matched) {
# Do some process
} else {
"Not Match"
# Do some process
}
Something like that you should test :
cls
$ID = #("8538", "8539", "8540", "85AC", "85DE", "82EA","8537")
$Signal = #("8537","8220","85DE")
for ($i = 0; $i -lt $ID.count; $i++) {
for ($j = 0; $j -lt $Signal.count; $j++) {
if ($ID[$i] -like $Signal[$j])
{
"found $($ID[$i]) at index $i"
# Do some process
}
else
{
"Not Match"
# Do some process
}
}
}
As mentioned in my comment above - to make your example work you can use a nested loop like this:
$ID = #("8537", "8538", "8539", "8540", "85AC", "85DE", "82EA")
$Signal = #("8234", "8512", "8220")
$MatchFound = $false
for ($i = 0; $i -lt $Signal.count; $i++) {
for ($x = 0; $x -lt $ID.Count; $x++) {
if ($Signal[$i] -eq $ID[$x]) {
"found '$($Signal[$i])' at index $i"
$MatchFound = $true
}
}
}
if (-not $MatchFound) {
"No match was found"
}
If you have a complex object you want to compare you can take a look at the cmdlet Compare-Object.

NOT an array reference error in Perl

I'm getting an error in Perl and I can't work out why.
Error: Not an ARRAY reference at Service.pm, line 20
my $array = [ { name => 'George', surname => 'Marley' } ];
my $helper = CustMessage->new();
$helper = CustMessage->getMessage($array);
then in my utility file I have:
sub getMessage {
my ($self, $args) = #_;
my $stringsArray = shift;
my $strings = Service->new({
serviceId => $self->_serviceId(),
});
return unless $strings;
$strings->getStrings($stringsArray);
}
and then in the Service method is:
sub getStrings {
my ($stringsArray, $self) = shift;
my #keys = map({ $_->{'name'} } #{$stringsArray});
my $key = join('', #keys);
$key = MIME::Base64::encode($key);
my %results;
$results{$key} = $self->_callStrings->($stringsArray);
$results{$key}->initialize();
$results{$key} = $self->{serviceCalls}->{getStrings};
return $self->{serviceCalls}->{getStrings};
}
The error is on line 2 of the getStrings method in Service.pm:
my #keys = map({ $_->{'name'} } #{$stringsArray});
The lines
my $helper = CustMessage->new();
$helper = CustMessage->getMessage($array);
are very odd. You are creating a new CustMessage object in $helper and immediately discarding it and overwriting it with the result of
CustMessage->getMessage($array);
which, apart from any inheritance that may be going on, is identical to
getMessage('CustMessage', $array);
and I am suspecting that you don't have a real class defined as you call it your "utility file"
Because getMessage receives its arguments like this
my ($self, $args) = #_;
my $stringsArray = shift;
you are left with
($self, $args) = ('CustMessage', $array)
$stringsArray = 'CustMessage'
and you never use $args again so your array reference is lost.
I cannot be sure what it is you actually want, because, as I said, I suspect that you don't have a proper CustMessage.pm file. But you could try
my $helper = CustMessage->new;
my $message = $helper->getMessage($array);
and then
sub getMessage {
my ($self, $stringsArray) = #_;
...
}
RE: I'm getting an error in Perl and I can't work out why. Error: Not an ARRAY reference at Service.pm, line 20
Try
my ($self, $stringsArray) = #_;
instead of
my ($stringsArray, $self) = shift;
# $self is always undef here due one element list assignment
since getStrings() is object method and object instance is always first element in #_ array.

Find product in database with "like" statement in cakephp

I have a function that searches in the database all products with the description like the user search, but it is not working. Where is the problem?
public function searchProduct(){
$search = $this->request->query('search');
$products = $this->Product->find("all",array('conditions'=>array('Description LIKE'=>"%$search%")));
if($this->Auth->user()!= null){
$userId = $this->Auth->user('id');
$user = $this->User->findById($userId);
$filters = $user['Filter'];
$arrayFiltersOfUser = array();
$arrayOfProductIds = array();
for($i = 0; $i < count($filters); $i++){
$arrayFiltersOfUser[$i] = $filters[$i]['id'];
}
for($i = 0; $i < count($products); $i++){
$arrayOfProductIds[$i] = $products[$i]['Product']['id'];
}
for($i = 0; $i < count($arrayOfProductIds); $i++){
$arrayFiltersOfProduct_aux[$i] = $this->FiltersProduct->findAllByProductId($arrayOfProductIds[$i]);
$array = $arrayFiltersOfProduct_aux[$i];
for($j = 0; $j < count($array); $j++){
$array2[$j] = $array[$j]['FiltersProduct']['filter_id'];
}
$containsAllValues = !array_diff($arrayFiltersOfUser, $array2);
if($containsAllValues == true){
$this->set("is_valid", "yes");
$this->set("_serialize", array("is_valid"));
}
else{
$this->set("is_valid", "no");
$this->set("_serialize", array("is_valid"));
}
}
}
$this->set("response", $products);
$this->set("_serialize", array("response"));
}
You're now searching for: %$search% and not the value of $search.
Try to replace
find("all",array('conditions'=>array('Description LIKE'=>"%$search%")));
with
find("all",array('conditions'=>array('Description LIKE'=>"%".$search."%")));
This should do the trick.

Perl: Create a hash from an array

If I have the following array
my #header_line = ('id', 'name', 'age');
How do I create a hash from it equivalent to the line below?
my %fields = { id => 0, name => 1, age => 2};
The reason I want to do this is so that I can use meaningful names rather than magic numbers for indexes. For example:
$row->[$fields{age}]; # rather than $row->[2]
my %fields;
#fields{#header_line} = (0 .. $#header_line);
my %fields = map { $header_line[$_] => $_ } 0..$#header_line;
You said in reply to a comment that this is coming from Text::CSV. This module has a way to import this into a hash for you.
$csv->column_names( #header_line );
$row = $csv->getline_hr( $FH );
print $row->{ 'id' };
my %fields = ();
for (my $i = 0; $i < scalar(#header_line); $i++) {
$fields{$header_line[$i]} = $i;
}
TIMTOWTDI
my %fields = ();
foreach my $field(#header_line)
{
$fields{$field} = scalar(keys(%fields));
}

Array Manipulation join with out split

#browser = ("NS", "IE", "Opera");
my $add_str = "Browser:";
$count = 0;
foreach (#browser) {
my $br = $_;
$browser[$count] = "$add_str:$br";
$count++ ;
}
is there any other way to do this ? best way ?
You could use map.
#browser = ("NS", "IE", "Opera");
my $add_str = "Browser";
#browser = map { "${add_str}:$_"; } #browser;
In Perl 5, the for loop aliases each item, so you can simply say
#!/usr/bin/perl
use strict;
use warnings;
my #browsers = qw/NS IE Opera/;
my $add_str = "Browser:";
for my $browser (#browsers) {
$browser = "$add_str:$browser";
}
print join(", ", #browsers), "\n";

Resources