What is the meaning of these empty array assignments in perl? - perl

foreach my $tp (#tpList)
{
print "inside function 14";
my $result1_fail = "";
$_=$tp;
next if(/^$/);
print "TP : $tp\n";
$result.="<h3>$tp</h3><BR>\n";
$result1_fail.="<h3>$tp</h3><BR>\n";
#------------------------------#
print "inside function 15";
***my #emptytables=();
my #tables=();***
#tables= getAllTables4TP($tp);
Please explain the meaning of my #emptytables=();
And also my #tables=();
is this used for defining some empty array?
if it is, then what is its use?

These initialize the arrays as empty and if the next thing is an array assignment, it's basically useless. I would write
my #tables = getAllTables4TP($tp);
I can't say anything about #emptytables because I don't see code using it.

my #tables; creates an empty array
my #tables = (); creates an empty array, then replaces its contents with nothing (empties it).
my #tables = (); #tables = getAllTables4TP($tp); creates an empty array, then replaces its contents with nothing, then replaces its contents with something else.
I would use just the following:
my #tables = getAllTables4TP($tp);

Yes you are correct, it's defining an empty array.
Check this part
my #tables=();
#tables= getAllTables4TP($tp);
Here the data insertion is done into the tables array. You can directly write the above lines as one line:
my #tables= getAllTables4TP($tp);

Related

Perl Split Function - How to assign a specify array value to a variable in one line

Is this a way of using a one-liner to assign an array value to a variable using the split function.
I have the following code. This works.
my #Fields = split(',',#_[0]);
my $Unit = #Fields[2];
Wondering if it could be written in one like the following, they are returning syntax errors.
my $Unit = split(',',#_[0])[2];
my $Unit = #(split(',',#_[0]))[2];
Your second one is very close. Drop that leading #:
my $Unit = (split(',', $_[0]))[2];
(Note $_[0] instead of the one-element array slice #_[0]... if you have use warnings; in effect like you should, that would give you one.)

map a string in each element of an array and assigning in another array in perl

I have an array #abc in which I have the values '1234.txt','2345.txt','3456.txt','4567.txt'.
I want to get all the numeric values from this array and put them in another array say #xyz.
I have the regex to do so but using map function I am not able to get the numeric values in another array.
Below code is the snipet of only the section where I am trying the map function:
use strict;
use warnings;
my #abc = ('1234.txt', '2345.txt', '3456.txt', '4567.txt');
foreach my $abc(#abc) {
my #xyz = map(m/(\d*).txt/, $abc);
print "#xyz\n";
}
With this code, I am getting below output:
1234
2345
3456
4567
but this is not an array as when I tried changning print "#xyz\n"; to print "$xyz[0]\n"; I am still getting the same output when the output should only be 1234. I guess the output is in the form of string not array.
Can anyone please help in getting these values in an array.
The problem is that your array #xyz will only ever contain one value, since your for loop takes one array element at the time. Then you assign the value of a single scalar through a map statement, to an array declared inside the for-loop, which means the array will be out of scope when the loop is done and no values are ever saved between loop iterations.
my #abc = ('1234.txt', '2345.txt', '3456.txt', '4567.txt');
foreach my $abc(#abc) { # using one array element at the time
my #xyz = map(m/(\d*).txt/, $abc); # single string, never saved
print "#xyz\n"; # only prints one value
}
Since #xyz only contains one value, it makes no difference if you print the entire array, or just the first element.
If you want this to work, you have to move the array outside the loop, and use push, not assignment = (the latter will overwrite). And remove the map statement, as it is redundant for single strings. Also, put the print statement outside the loop, or we will print some values multiple times.
my #abc = ('1234.txt', '2345.txt', '3456.txt', '4567.txt');
my #xyz; # declare outside loop
foreach my $abc(#abc) {
push #xyz, $abc =~ m/(\d*).txt/;
}
print "#xyz\n"; # print only after all values have been collected
But this is not the best way to do it. The for-loop is redundant if we use map. Both for and map loop around the values in a list/array, so doing it twice serves no purpose in this case. The solution, as has already been given by Wes and in comments:
my #abc = ('1234.txt', '2345.txt', '3456.txt', '4567.txt');
my #xyz = map { m/(\d+).txt/ } #abc;
print "#xyz\n";
Also, you should use \d+ when collecting numbers, as otherwise you will get empty string false positives for some strings. For example, the string foo.txt would return the empty string "". If you expect the whole file name to be numbers you should use a beginning-of-line anchor: /^(\d+)\.txt/. Also, period . should be escaped, because it is a regex meta character.
The problem is that you are using map for each value rather than calling it once, with the entire list. Instead, try this, which will build your #xyz array all at once and leave the four numbers/strings (they'll be strings but perl will convert them to integers if you try to use them as such):
use strict;
use warnings;
my #abc = ('1234.txt', '2345.txt', '3456.txt', '4567.txt');
my #xyz = map(m/(\d*).txt/, #abc);
print "#xyz\n";

Is it possible to dynamically expand a scalar assignment depending on the size of an array?

So, here's the deal. I have an array, let's call it
#array = ('string1','string2','string3','string4');
etc., etc. I have no way of knowing how large the array is or what the contents are, specifically, except that it is an array of strings.
I also have a variable which needs to be changed depending on the size and contents of the array.
Here's a sample easy assignment of that variable, along with the array that would have generated the assignment:
#array = ('string1','string2','string3');
$var = Some::Obj1(Some::Obj2('string1'),
Some::Obj2('string2'),
Some::Obj2('string3'));
Then, if for instance, I had the following #array,
#array = ('string1','string2','string3','string4','string5');
My assignment would need to look like this:
$var = Some::Obj1(Some::Obj2('string1'),
Some::Obj2('string2'),
Some::Obj2('string3'),
Some::Obj2('string4'),
Some::Obj2('string5'));
Can you guys think of any way that something like this could be implemented?
Well, if all you need is to turn some strings into a list of objects inside an object... Why not map?
my #array = ('string1','string2','string3','string4','string5');
my $var = Some::Obj1(map { Some::Obj2($_) } #array);
Yes, you just do
$var = Some::Obj1(map(Some::Obj2($_), #array));
That produces the exact same result as the code you wrote:
$var = Some::Obj1(Some::Obj2('string1'),
Some::Obj2('string2'),
Some::Obj2('string3'),
Some::Obj2('string4'),
Some::Obj2('string5'));
Of course, it goes without saying that you should use either my or our before the variable as appropriate if you are initializing it for the first time. If you wish to perform more complicated operations using map, an entire block of code can be enclosed in braces and the comma omitted, i.e.,
map {operation 1; operation 2; ...; final operation stored as result;} #array

Perl Array Dereference Problem with DBI::fetchall_arrayref

I'm a Perl newbie and am having issues with dereferencing an array that is a result of fetchall_arrayref in the DBI module:
my $sql = "SELECT DISTINCT home_room FROM $classlist";
my $sth = $dbh->prepare($sql);
$sth->execute;
my $teachers = $sth->fetchall_arrayref;
foreach my $teacher (#{$teachers}) {
print $teacher;
}
Running this will print the reference instead of the values in the array.
However, when I run:
my $arrref = [1,2,4,5];
foreach (#{$arrref}) {
print "$_\n";
}
I get the values of the array.
What am I doing wrong? Thank you for your help!
Jeff
From the doc
The fetchall_arrayref method can be
used to fetch all the data to be
returned from a prepared and executed
statement handle. It returns a
reference to an array that contains
one reference per row.
So in your example, $teacher is an ARRAY ref.
So you will need to loop through this array ref
foreach my $teacher (#{$teachers}) {
foreach my $titem (#$teacher) {
print $titem;
}
}
if you want to extract only the teacher column, you want to use:
my #teachers = #{$dbh->selectcol_arrayref($sql)};
fetchall_arrayref fetches all the results of the query, so what you're actually getting back is a reference to an array of arrays. Each row returned will be an arrayref of the columns. Since your query has only one column, you can say:
my $teachers = $sth->fetchall_arrayref;
foreach my $teacher (#{$teachers}) {
print $teacher->[0];
}
to get what you want.
See more:
Arrays of arrays in Perl.
You have a reference to an array of rows. Each row is a reference to an array of fields.
foreach my $teacher_row (#$teachers) {
my ($home_room) = #$teacher_row;
print $home_room;
}
You would have seen the difference with Data::Dumper.
use Data::Dumper;
print(Dumper($teachers));
print(Dumper($arrref));
$sth->fetchall_arrayref returns a reference to an array that contains one reference per row!
Take a look at DBI docs here.
Per the documentation of DBI's fetchall_arrayref():
The fetchall_arrayref method can be
used to fetch all the data to be
returned from a prepared and executed
statement handle. It returns a
reference to an array that contains
one reference per row.
You're one level of indirection away:
my $sql = "SELECT DISTINCT home_room FROM $classlist";
my $sth = $dbh->prepare($sql);
$sth->execute;
my $teachers = $sth->fetchall_arrayref;
foreach my $teacher (#{$teachers}) {
local $" = ', ';
print "#{$teacher}\n";
}
The data structure might be a little hard to visualize sometimes. When that happens I resort to Data::Dumper so that I can insert lines like this:
print Dumper $teacher;
I've found that sometimes by dumping the datastructure I get an instant map to use as a reference-point when creating code to manipulate the structure. I recently worked through a real nightmare of a structure just by using Dumper once in awhile to straighten my head out.
You can use map to dereference the returned structure:
#teachers = map { #$_->[0] } #$teachers;
Now you have a simple array of teachers.

Indexing directly into returned array in Perl

This question has been asked about PHP both here and here, and I have the same question for Perl. Given a function that returns a list, is there any way (or what is the best way) to immediately index into it without using a temporary variable?
For example:
my $comma_separated = "a,b,c";
my $a = split (/,/, $comma_separated)[0]; #not valid syntax
I see why the syntax in the second line is invalid, so I'm wondering if there's a way to get the same effect without first assigning the return value to a list and indexing from that.
Just use parentheses to define your list and then index it to pull your desired element(s):
my $a = (split /,/, $comma_separated)[0];
Just like you can do this:
($a, $b, $c) = #array;
You can do this:
my($a) = split /,/, $comma_separated;
my $a on the LHS (left hand side) is treated as scalar context. my($a) is list context. Its a single element list so it gets just the first element returned from split.
It has the added benefit of auto-limiting the split, so there's no wasted work if $comma_separated is large.