CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Beginner:
How to work with "structs" in Perl ??

 



PapaGeek
User

Feb 20, 2014, 11:21 AM

Post #1 of 12 (1688 views)
How to work with "structs" in Perl ?? Can't Post

I’m a C/C++ programmer learning Perl. I want to read a small database table into memory, sort it and make it available to the rest of the program in that sorted order. Each table entry has 3 fields that will go into the array of structures, of course that is my question! How do I create an array of structures that can be sorted on various columns?

The fields are:
ID: (integer) a unique ID assigned when each record is created, used for relational DB referencing.
Order: (integer) the order in which the user wants to display the data.
Name: (string) the name of the item assigned by the user.

This is only application one for the database access I want. Other application may have more or less fields and the fields might be things like a Boolean true/false, Cash, Date, Percentage, etc.

Another example is a directory list. Each entry includes a date/time, a number (size), and a string (filename). I may want to display the directory list sorted by any of those fields. In C you can create a struct DirectoryItem which will contain all 3 of those pieces, then create an array of those structures. There are a number of methods that could then be used to sort the array based on any structure field.


FishMonger
Veteran / Moderator

Feb 20, 2014, 11:43 AM

Post #2 of 12 (1686 views)
Re: [PapaGeek] How to work with "structs" in Perl ?? [In reply to] Can't Post

Perl doesn't have "strucs" like C/C++. The closest data type in perl would be a hash (associative array).

Personally, I'd do the sorting at the db level by using the ORDER BY clause. But. you could do the sorting in Perl if you wish.

See:
perldoc -f sort - http://perldoc.perl.org/functions/sort.html
Schwartzian transform - http://en.wikipedia.org/wiki/Schwartzian_transform
perl multiple field sort (google search) - https://www.google.com/search?q=perl+sort+fields+examples&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:en-US:official&client=firefox-a&channel=sb#channel=sb&q=perl%20multiple%20field%20sort&rls=org.mozilla:en-US:official


FishMonger
Veteran / Moderator

Feb 20, 2014, 11:48 AM

Post #3 of 12 (1684 views)
Re: [PapaGeek] How to work with "structs" in Perl ?? [In reply to] Can't Post

I assume you already know about Perl's db modules, but in case you don't, here's what you need.

DBI - Database independent interface for Perl
http://search.cpan.org/~timb/DBI-1.631/DBI.pm

DBD::mysql - MySQL database driver for Perl DBI
http://search.cpan.org/~capttofu/DBD-mysql-4.026/README.pod


PapaGeek
User

Feb 21, 2014, 8:47 AM

Post #4 of 12 (1634 views)
Re: [FishMonger] How to work with "structs" in Perl ?? [In reply to] Can't Post

I am a bit familiar with Perl’s data base options and I do know how to write the SQL to sort the data as I read it from the database, but I want to learn more about the syntax of Perl along the way. I plan to use ODBC and use MS Access for my initial database. I also plan to keep all of the database access in a separate .PM package so I can replace it easily at a later date.

OK, this is probably not the best way to do this, but I also want to learn more about hashes.

Here is a quickie program that uses “insertHash” to build an array of references to hashes, I hope this is working the way I want.

My next step would be to access each of the hash references and print the data from them, but I’m having problems with the syntax for extracting and then using the hash references from the array.

Here is the code followed by the output. It shows that the array is being built with two references (I hope), but then goes South when I try to print the data.

Code
use Modern::Perl '2013'; 

my %dataLine;
my @hashArray;

insertHash(3,7,"my 401K");
insertHash(2,5,"her 401K");

my $sizeOfArray = scalar (@hashArray);

print "The final array of hash references has $sizeOfArray items\n";
my $hashRef = $hashArray[0];

for (my $index = 0; $index < $sizeOfArray; $index++)
{
my $hashRef = $hashArray[$index];
foreach (sort keys {$hashRef}) { print "$_ : {$hashRef}{$_}\n"; }
}



sub insertHash {

my $ID = shift;
my $Order = shift;
my $name = shift;

my %dataLine;

$dataLine{"ID"} = $ID;
$dataLine{"Order"} = $Order;
$dataLine{"name"} = $name;

foreach (sort keys %dataLine) { print "$_ : $dataLine{$_}\n"; }
my $sizeOfArray = scalar (@hashArray);
print "Array is $sizeOfArray\n";
push (@hashArray, \%dataLine);

}


Code
ID : 3 
Order : 7
name : my 401K
Array is 0
ID : 2
Order : 5
name : her 401K
Array is 1
The final array of hash references has 2 items
HASH(0x6b3a54) : {HASH(0x6b3a54)}{HASH(0x6b3a54)}
HASH(0x5ffa3c) : {HASH(0x5ffa3c)}{HASH(0x5ffa3c)}
Odd number of elements in anonymous hash at C:/Users/Sandy/workspace/Quickie/QuickTest.pl line 17.
Odd number of elements in anonymous hash at C:/Users/Sandy/workspace/Quickie/QuickTest.pl line 17.



Laurent_R
Veteran / Moderator

Feb 21, 2014, 10:37 AM

Post #5 of 12 (1627 views)
Re: [PapaGeek] How to work with "structs" in Perl ?? [In reply to] Can't Post

Hi,

change line 17 to this:


Code
foreach (sort keys %{$hashRef}) { print "$_ : ", ${$hashRef}{$_}, "\n"; }


It should work properly.

Having said that, there are more consice and better ways to write many of the things you have in your code.

I might come back a bit later with a more concise version of your program.


Laurent_R
Veteran / Moderator

Feb 21, 2014, 10:52 AM

Post #6 of 12 (1625 views)
Re: [PapaGeek] How to work with "structs" in Perl ?? [In reply to] Can't Post

OK, this is a more concise form of your program:


Code
use Modern::Perl '2013'; 

my @hashArray;

insertHash(3,7,"my 401K");
insertHash(2,5,"her 401K");

print "The final array of hash references has ", scalar @hashArray, " items\n";

for my $hashRef (@hashArray) {
foreach (sort keys %{$hashRef}) { print "$_ : $$hashRef{$_} \n"; }
}

sub insertHash {
my %dataLine;

$dataLine{"ID"} = shift;
$dataLine{"Order"} = shift;
$dataLine{"name"} = shift;

foreach (sort keys %dataLine) { print "$_ : $dataLine{$_}\n"; }
print "Array is ", scalar @hashArray, "\n";
push @hashArray, \%dataLine;
}


Personnally, I would probably make it even more concise, but I wanted to keep close to your logic and make sure it is very understandable for you.


(This post was edited by Laurent_R on Feb 21, 2014, 10:55 AM)


PapaGeek
User

Feb 21, 2014, 11:57 AM

Post #7 of 12 (1620 views)
Re: [Laurent_R] How to work with "structs" in Perl ?? [In reply to] Can't Post

Thanks, that line did work. Now if you could help me to totally understand it! SMILE!

Perl syntax is still a bit confusing, so let me see if I understand what you did.

for my $hashRef (@hashArray) {
foreach (sort keys %{$hashRef}) { print "$_ : $$hashRef{$_} \n"; }



$hashRef - the reference to the hash as a scalar
{$hashRef} – Change it to reference a hash
%{$hashRef} – And dereference it – now it is an actual hash!

Not sure why the second syntax is different, so correct me if I’m wrong

$hashRef - the reference to the hash as a scalar
$hashRef{$_} – the trailing use of braces does the same as surrounding the reference with them, it is now a hash, and it is also dereferenced at the same time??
$$hashRef{$_} – the preceding $ is because what we are getting back from the hash is a scalar

Also, why is one loop a for loop and te other a foreach loop?

This is why I love the famous quote from Andrew S Tanenbaum from his Computer Networks book, “The good thing about standards is that there are so many to choose from.” Every language has its own standard syntax!


Chris Charley
User

Feb 21, 2014, 1:54 PM

Post #8 of 12 (1608 views)
Re: [PapaGeek] How to work with "structs" in Perl ?? [In reply to] Can't Post

$hashRef - the reference to the hash as a scalar
Right

{$hashRef} – Change it to reference a hash
%{$hashRef} – And dereference it – now it is an actual hash!

Those braces may be omitted and could just use: %$hashref

That is, the line may be written as:

foreach (sort keys %$hashRef) { print "$_ : $$hashRef{$_} \n"; }

Just to note, you may write:
$$hashRef{$_}

as

$hashRef->{$_}

I prefer the arrow dereference, but either way is correct.

Also, why is one loop a for loop and te other a foreach loop?

There is no difference, just use what is your preference. The only time a 'for' is necessary is in a 'C' style loop like

for (my $j = 0; $j < @hashArray; $j++) {
. . .
}



(This post was edited by Chris Charley on Feb 21, 2014, 2:00 PM)


Laurent_R
Veteran / Moderator

Feb 21, 2014, 2:52 PM

Post #9 of 12 (1597 views)
Re: [PapaGeek] How to work with "structs" in Perl ?? [In reply to] Can't Post

OK, Chris has explained more or less everything. I have nothing to add or amend to what he said.

I still want to come back to the crucial part of the program:


Code
for my $hashRef (@hashArray) {   
foreach (sort keys %{$hashRef}) { print "$_ : $$hashRef{$_} \n"; }
}


The main point is that, once you have really made your mind that an array of hashes (AoH) is really a simple array of scalar values in which those scalar values are simply references to hashes (and the way you wrote your subroutine seems to indicate that you understand that at least to a certain extent, but perhaps don't draw all the conclusions from it), then you know that simply going through the array value will yield you in a very simple way the hashrefs that you need. Once you have this list of hashrefs, you just need to dereference them to get to the inner data.

Your error seems to be that you thought that using {$hashref} would give you access to the hash. This is wrong! The curlies dont help here. What you need to access to the hash refered to by $hashref (as a hash) is either of the following: %{$hashref} or %$hashref. If you want to access to individual elements of the hash, then you need to use ${$hashRef}{$_}, $$hashRef{$_} or $hashRef->{$_} (there may be other ways, but at least those should work).

I hope this helps. Please ask if you don't understand something in the above.


Kenosis
User

Feb 21, 2014, 3:18 PM

Post #10 of 12 (1593 views)
Re: [PapaGeek] How to work with "structs" in Perl ?? [In reply to] Can't Post

If I may build upon Laurent_R's excellent refactoring, I'd like to suggest avoiding directly accessing variables from within a subroutine, as this can cause many headaches later. Instead, pass a reference to a variable to the subroutine and dereference it within that subroutine:

Code
use Modern::Perl '2013'; 

my @hashArray;

insertHash( 3, 7, "my 401K", \@hashArray );
insertHash( 2, 5, "her 401K", \@hashArray );

print "The final array of hash references has ", scalar @hashArray, " items\n";

for my $hashRef (@hashArray) {
foreach ( sort keys %{$hashRef} ) { print "$_ : $$hashRef{$_} \n"; }
}

sub insertHash {
my %dataLine;

$dataLine{"ID"} = shift;
$dataLine{"Order"} = shift;
$dataLine{"name"} = shift;
my $hashArrayRef = shift;

foreach ( sort keys %dataLine ) { print "$_ : $dataLine{$_}\n"; }
print "Array is ", scalar @$hashArrayRef, "\n";
push @$hashArrayRef, \%dataLine;
}


Hope this helps!


(This post was edited by Kenosis on Feb 21, 2014, 11:41 PM)


PapaGeek
User

Feb 21, 2014, 5:02 PM

Post #11 of 12 (1585 views)
Re: [Kenosis] How to work with "structs" in Perl ?? [In reply to] Can't Post

All of the comments have been extremely helpful, I thank all of you for them. What is the best way to learn all of the nuances that everyone here is offering to me? I learn best by video courses, but anything will do. My name PapaGeek was given to me by the people I’ve worked with. I programmed my first computer back in 1967 for the US Army. I started playing with web development in 1993 and got my first web domain in 1995, just before Windows 95 made the internet popular.

I want to learn and master Perl, but since it is open source, there seems to be a lot of variations and many of the leads I find in the various forums are sort of dead ends. A lot of what I’ve learned has been trial and error, and that is not the best method for learning things the right way.


Laurent_R
Veteran / Moderator

Feb 22, 2014, 3:46 AM

Post #12 of 12 (1534 views)
Re: [PapaGeek] How to work with "structs" in Perl ?? [In reply to] Can't Post

The version offered by Kenosis is definitely better practice, I actually considered making the change he suggested but did not do it because I did not want to change too much to the logic of your original script (to let you concentrate on the changes I made) and also because , in that specific simple case, using a global array was in my mind a rather minor defect. So yes, passing a reference to the array into the subroutine is usually better than using directly the global array variable.



Quote
... there seems to be a lot of variations and many of the leads I find in the various forums are sort of dead ends


Perl's main motto is: "There is more than one way to do it", often abbreviated as TIMTOWTDI.

Asides from the error in the foreach loop (which I corrected in my first post), your program was correct, clean and perfectly acceptable, even for production code. I offered a refactored version just to to show you some more idiomatic, more "Perlish", ways of doing things. More idiomatic, but probably not more correct, you would be perfectly fine to use your code (with the correction in the loop) as it was. My version is just IMHO shorter, quicker and easier to write, and thus less prone to errors, this is why I wanted to show it to you.

Having said that, if you're really looking for "right" ways of doing things, I would suggest that you be a bit careful with videos and other tutorials on the Internet, some are good but it is not always the case. I think that buying a good book written by recognized authors is probably a good idea. My suggestions would be for the books published by O'Reilly, especially "Learning Perl" to start with and "Programming Perl" to follow up. They are really authoritative.


Quote
A lot of what I’ve learned has been trial and error, and that is not the best method for learning things the right way.


I tend to disagree with this. I think everyone of us learn a lot from our errors (and also sometimes from others' errors when we happen to see them). I think that your approach consisting in posting your code on this forum and asking for advice or corrections is very good, you are likely to learn a lot in this way. But, of course, use your judgement to evaluate the comments to receive, not every comment that you receive will be correct.

I hope this helps.

 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives