What is the proper way to dereference a multidimensional array in Perl? - perl

In my code I have a multidimensional array
$rows[$x][$y]
I am passing it to a sub function with multiple uses but at some point that function will need to remove (pop) one of the elements from the main array.
I believe the proper way to pass it is by referencing it since I am passing more than just the array:
filterout(\#rows, $y, $data );
But am unsure of the syntax to dereferencing it on the subroutine side.
Would appreciate any help, thanks as alway.

To pop from an array reference, use
my $last = pop #$aref;
Or, in more recent Perl versions,
my $last = pop $aref->#*;
To pop the inner array, you need to dereference the given element of the array reference:
my $last = pop #{ $aref->[$index] };
or
my $last = pop $aref->[$index]->#*;

It's an array ref pointing to an array of array refs pointing to arrays of scalars. So you'll need two de-references for a single element, one for a column and none for a row:
sub filterout(\#$$) {
my($array_ref, $y, $data) = #_;
# single element <row>,<col>
$array_ref->[ <row >]->[ <column> ] = ...;
# pop column of <row>
pop(#{ $array_ref->[ <row> ] });
# pop row
pop(#{ $array_ref });
}
filterout(#rows, $y, $data);
Note the prototype, which makes filterout() work like push().

Related

perl reference and dereference on return statement

I am learning perl, and have a problem related to references.
I am working on the function get_id.
If i return $self->{_id}, I will get two array address which cannot run (c).
In my understanding, $a is the reference and #{$a} is array and #{$a}[0] would return the value 0?
This is my first time post question on stackoverflow, therefore the explaination may not clear enough, sorry about that.
#a1 = [0]
#a2 = [1]
my self{
_id = [\#a1,\#a2]; } //given
sub get_id(){
my $self = shift;
return $self->{_id};
}
sub print{
...
my $a = $obj -> get_id();
my $b = #{$a}[0] * 100; // c (given)
..
}
When $arr is a reference to an array, #$arr or #{ $arr } is the array it refers to. The first (or zeroth) element of the array is $arr->[0] (or $$arr[0], but the arrow notation is more common).
The following
my #arr = [0];
creates an array with a single element, and that element is an array reference. To get the 0, you need to do
$arr[0]->[0]
which can be shortened to
$arr[0][0]
To create an array with 0 as the single element, use
my #arr = (0);
BTW, don't use $a and $b, they are special variables used in sort. Lexicalising them with my can lead to bugs that are hard to debug.

Perl find out if X is an element in an array

I don't know why small things are too not working for me in Perl. I am sorry for that.
I have been trying it around 2 hrs but i couldn't get the results.
my $technologies = 'json.jquery..,php.linux.';
my #techarray = split(',',$technologies);
#my #techarray = [
# 'json.jquery..',
# 'php.linux.'
# ];
my $search_id = 'json.jquery..';
check_val(#techarray, $search_id);
And i am doing a "if" to search the above item in array. but it is not working for me.
sub check_val{
my #techarray = shift;
my $search_id = shift;
if (grep {$_ eq $search_id} #techarray) {
print "It is there \n";
}else{
print "It is not there \n";
}
}
Output: It always going to else condition and returns "It is not there!" :(
Any idea. Am i done with any stupid mistakes?
You are using an anonymous array [ ... ] there, which as a scalar (reference) is then assigned to #techarray, as its only element. It is like #arr = 'a';. An array is defined by ( ... ).
A remedy is to either define an array, my #techarray = ( ... ), or to properly define an arrayref and then dereference when you search
my $rtecharray = [ .... ];
if (grep {$_ eq $search_id} #$rtecharray) {
# ....
}
For all kinds of list manipulations have a look at List::Util and List::MoreUtils.
Updated to changes in the question, as the sub was added
This has something else, which is more instructive.
As you pass an array to a function it is passed as a flat list of its elements. Then in the function the first shift picks up the first element,
and then the second shift picks up the second one.
Then the search is over the array with only 'json.jquery..' element, for 'php.linux.' string.
Instead, you can pass a reference,
check_val(\#techarray, $search_id);
and use it as such in the function.
Note that if you pass the array and get arguments in the function as
my (#array, $search_id) = #_; # WRONG
you are in fact getting all of #_ into #array.
See, for example, this post (passing to function) and this post (returning from function).
In general I'd recommend passing lists by reference.

Why does perl only dereference the last index when the range operator is used?

I have an array, #array, of array references. If I use the range operator to print elements 1 through 3 of #array, print #array[1..3], perl prints the array references for elements 1 through 3.
Why when I try to dereference the array references indexed between 1 and 3, #{#array[1..3]}, perl only dereferences and prints out the last element indexed in the range operator?
Is there a way to use the range operator while dereferencing an array?
Example Code
#!/bin/perl
use strict;
use warnings;
my #array = ();
foreach my $i (0..10) {
push #array, [rand(1000), int(rand(3))];
}
foreach my $i (#array) {
print "#$i\n";
}
print "\n\n================\n\n";
print #{#array[1..3]};
print "\n\n================\n\n";
From perldata:
Slices in scalar context return the last item of the slice.
#{ ... } dereferences a scalar value as an array, this implies that the value being dereferenced is in scalar context. From the perldata quote above we know that this will return the last element. Therefore the result is the last element.
A more reasonable approach would be to loop through your slice and print each individual array reference:
use strict;
use warnings;
use feature qw(say);
my #array_of_arrayrefs = (
[qw(1 2 3)],
[qw(4 5 6)],
[qw(7 8 9)],
[qw(a b c)],
);
foreach my $aref ( #array_of_arrayrefs[1..3] ) {
say join ',', #$aref;
}
#{#array[1..3]} is a strange-looking construct. #{ ... } is the array dereference operator. It needs a reference, which is a type of scalar. But #array[ ... ] produces a list.
This is one of those situations where you need to remember the rule for list evaluation in scalar context. The rule is that there is no general rule. Each list-producing operator does its own thing. In this case, apparently the array slice operator used in scalar context returns the last element of the list. #array[1..3] in scalar context is the same as $array[3].
As you have noticed, this is not useful. Array slices aren't meant to be used in scalar context
If you want to flatten a 2-dimensional nested array structure into a 1-dimensional list, use map:
print join ' ', map { #$_ } #array[1..3]
You still use the range operator for slicing. You just need some kind of looping construct (e.g. map) to apply the array dereference operator separately to each element of the outer array.
The #{ ... } construction dereferences the scalar value of the code within the braces as an array
I'm unclear what you expect from #{ #array[1..3] }, but the list#array[1..3] in scalar context returns just the last element of the list -- $array[3] -- so you are asking for #{ $array[3] } which I guess is what you got
If you explain what you want to print then I am sure we can help, but dereferencing a list makes little sense
#array[1..3] is a list of 3 array references. You can't dereference them all at once, so you should iterate over this list and dereference each element separately:
print #$_ for #array[1..3];
print "#$_\n" for #array[1..3]; # for better looking output

perl, function only printing first element of the array

I have an array that has several elements on it but when I pass the array as a parameter to a function and then call the function it only prints out the first element of the array multiple times. For example
my $element;
my $random_variable = "Testing";
my #the_array = ("hello", "bye", "hey");
foreach $element(#the_array)
{
PrintFunction(#the_array, $random_variable)
}
sub PrintFunction{
my ($the_array, $random_variable) = #_;
// other code here
print $the_array . "\n";
}
The result I get from this is
hello
hello
hello
The result I want is to print all the elements of the array as
hello
bye
hey
Change:
PrintFunction(#the_array, $random_variable)
to:
PrintFunction($element, $random_variable)
Your code passes the entire array to the sub, then you only print the 1st element of the array each time because you use the scalar variable $the_array inside the sub. Since foreach grabs each element of the array, you probably meant to use $element.
Add Print #_; to your sub to see what is passed to it. You will see:
hellobyeheyTesting
hellobyeheyTesting
hellobyeheyTesting
It means you are passing the entire array followed by the $random_variable. Therefore, $the_arrayin the sub will be always the first elements of #the_array which is hello. To fix that, you should pass each element of array iteratively by
foreach $element(#the_array)
{
PrintFunction(#element, $random_variable)
}

Perl: Beginner. Which data structure should I use?

Okay, not sure where to ask this, but I'm a beginner programmer, using Perl. I need to create an array of an array, but I'm not sure if it would be better use array/hash references, or array of hashes or hash of arrays etc.
I need an array of matches: #totalmatches
Each match contains 6 elements(strings):
#matches = ($chapternumber, $sentencenumber, $sentence, $grammar_relation, $argument1, $argument2)
I need to push each of these elements into the #matches array/hash/reference, and then push that array/hash/reference into the #totalmatches array.
The matches are found based on searching a file and selecting the strings based on meeting the criteria.
QUESTIONS
Which data structure would you use?
Can you push an array into another array, as you would push an element into an array? Is this an efficient method?
Can you push all 6 elements simultaneously, or have to do 6 separate pushes?
When working with 2-D, to loop through would you use:
foreach (#totalmatches) {
foreach (#matches) {
...
}
}
Thanks for any advice.
Which data structure would you use?
An array for a ordered set of things. A hash for a set of named things.
Can you push an array into another array, as you would push an element into an array? Is this an efficient method?
If you try to push an array (1) into an array (2), you'll end up pushing all the elements of 1 into 2. That is why you would push an array ref in instead.
Can you push all 6 elements simultaneously, or have to do 6 separate pushes?
Look at perldoc -f push
push ARRAY,LIST
You can push a list of things in.
When working with 2-D, to loop through would you use:
Nested foreach is fine, but that syntax wouldn't work. You have to access the values you are dealing with.
for my $arrayref (#outer) {
for my $item (#$arrayref) {
$item ...
}
}
Do not push one array into another array.
Lists just join with each other into a new list.
Use list of references.
#create an anonymous hash ref for each match
$one_match_ref = {
chapternumber => $chapternumber_value,
sentencenumber => $sentencenumber_value,
sentence => $sentence_value,
grammar_relation => $grammar_relation_value,
arg1 => $argument1,
arg2 => $argument2
};
# add the reference of match into array.
push #all_matches, $one_match_ref;
# list of keys of interest
#keys = qw(chapternumber sentencenumber sentence grammer_relation arg1 arg2);
# walk through all the matches.
foreach $ref (#all_matches) {
foreach $key (#keys) {
$val = $$ref{$key};
}
# or pick up some specific keys
my $arg1 = $$ref{arg1};
}
Which data structure would you use?
An array... I can't really justify that choice, but I can't imagine what you would use as keys if you used a hash.
Can you push an array into another array, as you would push an element into an array? Is this an efficient method?
Here's the thing; in Perl, arrays can only contain scalar variables - the ones which start with $. Something like...
#matrix = ();
#row = ();
$arr[0] = #row; # FAIL!
... wont't work. You will have to instead use a reference to the array:
#matrix = ();
#row = ();
$arr[0] = \#row;
Or equally:
push(#matrix, \#row);
Can you push all 6 elements simultaneously, or have to do 6 separate pushes?
If you use references, you need only push once... and since you don't want to concatenate arrays (you need an array of arrays) you're stuck with no alternatives ;)
When working with 2-D, to loop through would you use:
I'd use something like:
for($i=0; $i<#matrix; $i++) {
#row = #{$matrix[$i]}; # de-reference
for($j=0; $j<#row; $j++) {
print "| "$row[$j];
}
print "|\n";
}
Which data structure would you use?
Some fundamental container properties:
An array is a container for ordered scalars.
A hash is a container for scalars obtained by a unique key (there can be no duplicate keys in the hash). The order of values added later is not available anymore.
I would use the same structure like ZhangChn proposed.
Use a hash for each match.
The details of the match then can be accessed by descriptive names instead of plain numerical indices. i.e. $ref->{'chapternumber'} instead of $matches[0].
Take references of these anonymous hashes (which are scalars) and push them into an array in order to preserve the order of the matches.
To dereference items from the data structure
get an item from the array which is a hash reference
retrieve any matching detail you need from the hash reference