Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is ( @{ $value{$value}} ) in perl?

Tags:

perl

I have been working for weeks on trying to make a perl program work. Someone else wrote it and since then the data source has been changed. I have spent weeks searching line by line and doing tutorials. I am stuck. The code says @{ $Routings{$Code} } which has a list of values [ $ProcessID, $Setup, $Process ] but at the bottom of the code when foreach ( @{ $Routings{$Code} } ) {my $ProcessCodeID = @$_[0];} it does not seem to be returning the data. If anyone could even help me print $ProcessCodeID so I can track the data it would be extremely helpful.

Also if you could explain what @{$value{$key}} represents that would really help too.

Thanks heaps.

%Routings = ();
my $dbh = DBI-> connect('dbi:ODBC:SQL')
    or die "Couldn't open Databaxe: $DBI::errstr;  stopped";

my $query= $dbh->prepare("SELECT Code, Setup, Process, ProcessID FROM ROUTING");

$query->execute() or die "Couldn't execute statement: $DBI::errstr; stopped";

while ( my ($Code, $setup, $process, $processid) = $query->fetchrow_array() ){
    push ( @{ $Routings{$Code} }, [ $ProcessID, $Setup, $Process ] );
}

foreach ( @{ $Routings{$Code} } ) {
    my $ProcessCodeID = @$_[0];
    my $SetupMins = @$_[1];
    my $ProcessMins = @$_[2];
}
like image 710
user1340197 Avatar asked Dec 05 '22 16:12

user1340197


1 Answers

First of all it is important that you use strict and use warnings at the start of your program, and declare all your variables at the point they are first used. This will cause Perl to generate some very useful messages that will reveal many simple errors that are easily overlooked.

As an example, you are assigning the variables $setup, $process, and $processid but then pushing $Setup, $Process, and $ProcessID onto an array. Perl identifiers are case-sensitive so these are three diffferent variables and will have a value of undef at this point. use strict would have printed a compilation error saying that $ProcessID etc. hadn't been declared. (If you have a choice, it is better to use lower-case plus underscore for local identifiers like these. Seasoned Perl programmers will thank you.)

You should experiment with the Data::Dumper module which will show the contents and structure of a complex nested Perl data structure like this. Once you have use Data::Dumper in your program you can write

print Dumper \%Routings

which will show the contents of %Routings as an anonymous hash.

The value of each element $Routings{$Code} of the hash is a list (a reference to an array) of all the sets of ProcessID, Setup, and Process that correspond to that value of Code. (I presume the column Code is non-unique, otherwise the data structure is more complex than it needs to be.) So the first set of three values for a given $Code is at $Routings{$Code}[0] and the ProcessID for that set is $Routings{$Code}[0][0].

There is no code to assign a value to $Code for the foreach loop, and presumably you would want to loop over all the keys of the %Routings hash.

Each time round the foreach loop $_ is set to a reference to each triplet of values for the current $Code. That means @$_ is a three-element array, but it should be indexed using $_->[0] etc. instead of @$_[0] which is a one-element array slice and poor coding practice. The code is made more obscure by using the default $_ here and I have clarified it below by using a named variable.

The code below fixes the problems I can see. Please come back if you need any further help.

use strict;
use warnings;

use DBI;

my %Routings;

my $dbh = DBI-> connect('dbi:ODBC:SQL')
    or die "Couldn't open Databaxe: $DBI::errstr;  stopped";

my $query= $dbh->prepare("SELECT Code, Setup, Process, ProcessID FROM ROUTING");

$query->execute or die "Couldn't execute statement: $DBI::errstr; stopped";

while ( my ($Code, $Setup, $Process, $ProcessID) = $query->fetchrow_array ){
  push @{ $Routings{$Code} }, [ $ProcessID, $Setup, $Process ];
}

for my $Code (keys %Routings) {
  foreach my $triplet ( @{ $Routings{$Code} } ) {
    my $ProcessCodeID = $triplet->[0];
    my $SetupMins = $triplet->[1];
    my $ProcessMins = $triplet->[2];
    print "$Code => ($ProcessCodeID, $SetupMins, $ProcessMins)\n";
  }
}

Note that the assignments within the foreach loop can be made clearer and more concise by performing them all at once. As I have explained, @$triplet is a three-element array, so the equivalent assignment could be coded as simply

my ($ProcessCodeID, $SetupMins, $ProcessMins) = @$triplet;

(Please treat this code warily, as I cannot test it it thoroughly without significant work setting up a test database, although it does work correctly on a simple data set.)

like image 65
Borodin Avatar answered Dec 13 '22 10:12

Borodin