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.

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.

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.

$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!

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.

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:

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.

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.