Softpanorama

May the source be with you, but remember the KISS principle ;-)
Home Switchboard Unix Administration Red Hat TCP/IP Networks Neoliberalism Toxic Managers
(slightly skeptical) Educational society promoting "Back to basics" movement against IT overcomplexity and  bastardization of classic Unix

Introduction to Perl 5.10 for Unix System Administrators

(Perl 5.10 without excessive complexity)

by Dr Nikolai Bezroukov

Contents : Foreword : Ch01 : Ch02 : Ch03 : Ch04 : Ch05 : Ch06 : Ch07 : Ch08 :


Prev | Up | Contents | Down | Next

Array of Arrays and Hashes of Arrays 


Complex data structure are created from basic data structures available in the language such as scalars, hashes and arrays.  This is difficult to do if the language does not have pointers/references as a data type. In this area Perl is superior to other scripting languages as it includes references as the basic data type.

Good explanation of this topic can also be found in Chapter 9 Data Structures of Programming Perl (Third Edition) by Larry Wall, Tom Christiansen, and Jon Orwant. It is freely available from O'Reilly website

You also can benefit from reading several documents written by Tom Christiansen and distributed with Perl documentation:

Array of Arrays

One interesting thing that we discovered is that Perl supports only one dimensional arrays and there is no structures that contain different complex types of variables as members.  References allow Perl to solve this problems.  Using them we can construct an array of arrays (matrix) which is very similar to two dimentional arrays that exists in C. Elements of this matrix in Perl do not need to be homogeneous. They can be anything, some element can be scalar, some arrays, some hashes, etc.

Constructing an array of arrays

First, remember that the list of elements in square brackets (for example ['Jan', 'Feb', 'Mar']), makes an anonymous array, and gives you a reference to that array. To create such a matrix we can use standard Perl array creation construct.  For example: 

@matrix =( 
            ['Jan', 'Feb', 'Mar'],
            ['Apr', 'May','Jun'],
            ['Jul', 'Aug', 'Sep'],
            ['Oct', 'Nov', 'Dec'],
         );

Now matrix became an array with four elements. Each of them is a reference to another (anonymous) array with three elements. For example, $matrix[1] is the reference to the second anonymous array (indexes start with zero) containing ['Apr', 'May', 'Jun'], and because it is a reference to an array, we can write $matrix[1]->[2] to get the third element from that array which should be "Jun".  This notation can be abbreviated as in Perl between two subscripts, the arrow is optional. That means that instead of $matrix[1]->[2], we can write $matrix[1][2]. In other words we can use standard notation for multidimensional arrays in Perl.

Arrays do not need to be homogeneous, they can contain string values and numeric values intermixed. for example:

@orders = [
[ 25.5, 'George Washington',Priority','GOOD'],
[ 132, 'Abraham Lincoln','Express','CANCELED'],
[ 543.3, 'Theodore Roosevelt','Ground','GOOD']
];

Again, to check what particular element of array contains you can use function ref.

You can use the module Data::Dumper to print the array:

use Data::Dumper;
print Dumper(@orders);

Adding data to array of array

Let's read in a data structure from a file and add several new rows (as many as there are record in our datafile) to the array of array:

while (<>) {
    @tmp = split;         # Split elements into an array.
    push @X, [ @tmp ];    # Add an anonymous array reference to @AoA.
}

If we need to add a column that means adding one element to each array referenced by the first dimetion of array of arrays:

for $x (0 .. 4) {                       # For each row...
    for $y (0 .. 4) {                   # For each column...
        $X[$x][$y] = func($x, $y);    # ...set that cell
    }
}
for $x ( 0..9 ) {                       # For each row...
    $ref_to_AoA->[$x][3] = func2($x);   # ...set the fourth column
}
If you just want to append to a row, you ca use push of the subarray. Unfortunately the notation is tricky: 
push(@$X[0], "galant", "outlander");
The argument to push must be a real array, not just a reference to an array. Therefore, the first argument absolutely must begin with an @ character.

Printing array of array

Now let's print the data structure. If you only want one element, this is sufficient:

print $X[3][2];
But if you want to print the whole thing, you can't just say:
print @X;         # WRONG

It's wrong because you'll see "stringified" references instead of your data. Perl never automatically dereferences for you. Instead, you have to roll yourself a loop or two. The following code prints the whole structure, looping through the elements of @AoA and dereferencing each inside the print statement:

for $row ( @X ) {
    print "@$row\n";
}
If you want to keep track of subscripts, you might use an inner loop:
for $i ( 0 .. $#X ) {
    for $j ( 0 .. $#{$X[$i]} ) {
        print "element $i $j is $X[$i][$j]\n";
    }
}

Hashes of Arrays

Hashes of arrays are very similar to arrays of arrays. You can create a hash of anonymous arrays as follows:

%hosts = (
    "Solarus"  => [ "T4-1", "Fire X4888" ],
    "Linux"    => [ "PE1950", "PE2950", "ProLiant 370G7", "ProLiant 580G7" ],
    "AIX"      => [ "Power 710", "Power 720", "Power 730" ],
);
To add another array to the hash, you can simply say:
$hosts{"HP-UX"} = [ "RX1620", "RX2660", "RX5670", "RX8640" ];

Access and Printing of Elements of a Hash of Arrays

You can replace an element of  a particular array as follows:

$hosts{"Solaris"}[0] = "mark";
You can print all of the Unix flavors by looping through the keys of the hash:
for $unix_flavour ( keys %hosts ) {
    print "$unix_flavour: @{$hosts{$unix_flavour}}\n";
}
With a little extra effort, you use the nested loops to get more control over how the array is printed:
for $unix_flavour ( keys %hosts ) {
    print "$unix_flavour: ";
    for $i ( 0 .. $#{ $hosts{$unix_flavour} } ) {
        print "$hosts{$family}[$i]";
    }
    print "\n";
}

A More Complex Example

Let's assume that we need to keed data about filesystem as depicted by df command in the form of hash or arrays. Here is how to accomplish this task: 

01 @df_filtered=`df -k | egrep "^/dev/"`;
02 foreach $line (@df_filtered) {
03    chomp($line);
04    @df_tokens = split(/\s+/, $line);
05    $fs=pop(@df_tokens);
06    $ref=[@df_tokens];
07    $df_table{$fs}=$ref;
08 } #foreach

The program has two pieces: The first like extract from output of df command lines that start with /dev and the second is for loop where we construct the hash of arrays

In the for loop the line 6 is the important one. That's where we allocate anonimous array that contains values for the current filesystem. In Line 7 we assign reference to newly create anonimous array as the value of hash entry for the filesystem. 

The rest of the program is just familiar uses of split, pop, and print, and doesn't involve references at all.

Common Mistakes

Perl arrays and hashes are one-dimensional. In Perl, even "multidimensional" arrays are actually one-dimensional, but the values along the first dimension are references to other arrays. When you print data you need manually dereference them. Perl will not do it for you automatically. Here is an example from Chapter 9 of  Programming Perl:

@AoA = ( [2, 3], [4, 5, 7], [0] );
print "@AoA";
result in something like:
ARRAY(0x83c38) ARRAY(0x8b194) ARRAY(0x8b1d0)
On the other hand, this line displays 7:
print $AoA[1][2];

When constructing an array of arrays, remember to compose new references for the subarrays. Otherwise, you If you construct an array of array you need to ensure that each element has its own subarray, Typical mistake people naturally make involves taking a reference to the same memory location over and over again. Here is another example from Programming Perl:

for $i (1..10) {
    @array = somefunc($i);
    $AoA[$i] = \@array;      # WRONG AGAIN!
}
Every reference generated by the second line of the for loop is the same, namely, a reference to the single array @array. Yes, this array changes on each pass through the loop, but when everything is said and done, $AoA contains 10 references to the same array, which now holds the last set of values assigned to it. print @{$AoA[1]} will reveal the same values as print @{$AoA[2]}.

Here's a more successful approach:

for $i (1..10) {
    @array = somefunc($i);
    $AoA[$i] = [ @array ];   # RIGHT!
}
The brackets around @array create a new anonymous array, into which the elements of @array are copied. We then store a reference to that new array.

... ... ...

Finally, the following dangerous-looking code actually works fine:

for $i (1..10) {
    my @array = somefunc($i);
    $AoA[$i] = \@array;
}
That's because the lexically scoped my @array variable is created afresh on each pass through the loop. So even though it looks as though you've stored the same variable reference each time, you haven't. This is a subtle distinction, but the technique can produce more efficient code, at the risk of misleading less-enlightened programmers. (It's more efficient because there's no copy in the final assignment.) On the other hand, if you have to copy the values anyway (which the first assignment in the loop is doing), then you might as well use the copy implied by the brackets and avoid the temporary variable:
for $i (1..10) {
    $AoA[$i] = [ somefunc($i) ];
}
In summary:
$AoA[$i] = [ @array ];   # Safest, sometimes fastest
$AoA[$i] = \@array;      # Fast but risky, depends on my-ness of array

Prev | Up | Contents | Down | Next



Etc

Society

Groupthink : Two Party System as Polyarchy : Corruption of Regulators : Bureaucracies : Understanding Micromanagers and Control Freaks : Toxic Managers :   Harvard Mafia : Diplomatic Communication : Surviving a Bad Performance Review : Insufficient Retirement Funds as Immanent Problem of Neoliberal Regime : PseudoScience : Who Rules America : Neoliberalism  : The Iron Law of Oligarchy : Libertarian Philosophy

Quotes

War and Peace : Skeptical Finance : John Kenneth Galbraith :Talleyrand : Oscar Wilde : Otto Von Bismarck : Keynes : George Carlin : Skeptics : Propaganda  : SE quotes : Language Design and Programming Quotes : Random IT-related quotesSomerset Maugham : Marcus Aurelius : Kurt Vonnegut : Eric Hoffer : Winston Churchill : Napoleon Bonaparte : Ambrose BierceBernard Shaw : Mark Twain Quotes

Bulletin:

Vol 25, No.12 (December, 2013) Rational Fools vs. Efficient Crooks The efficient markets hypothesis : Political Skeptic Bulletin, 2013 : Unemployment Bulletin, 2010 :  Vol 23, No.10 (October, 2011) An observation about corporate security departments : Slightly Skeptical Euromaydan Chronicles, June 2014 : Greenspan legacy bulletin, 2008 : Vol 25, No.10 (October, 2013) Cryptolocker Trojan (Win32/Crilock.A) : Vol 25, No.08 (August, 2013) Cloud providers as intelligence collection hubs : Financial Humor Bulletin, 2010 : Inequality Bulletin, 2009 : Financial Humor Bulletin, 2008 : Copyleft Problems Bulletin, 2004 : Financial Humor Bulletin, 2011 : Energy Bulletin, 2010 : Malware Protection Bulletin, 2010 : Vol 26, No.1 (January, 2013) Object-Oriented Cult : Political Skeptic Bulletin, 2011 : Vol 23, No.11 (November, 2011) Softpanorama classification of sysadmin horror stories : Vol 25, No.05 (May, 2013) Corporate bullshit as a communication method  : Vol 25, No.06 (June, 2013) A Note on the Relationship of Brooks Law and Conway Law

History:

Fifty glorious years (1950-2000): the triumph of the US computer engineering : Donald Knuth : TAoCP and its Influence of Computer Science : Richard Stallman : Linus Torvalds  : Larry Wall  : John K. Ousterhout : CTSS : Multix OS Unix History : Unix shell history : VI editor : History of pipes concept : Solaris : MS DOSProgramming Languages History : PL/1 : Simula 67 : C : History of GCC developmentScripting Languages : Perl history   : OS History : Mail : DNS : SSH : CPU Instruction Sets : SPARC systems 1987-2006 : Norton Commander : Norton Utilities : Norton Ghost : Frontpage history : Malware Defense History : GNU Screen : OSS early history

Classic books:

The Peter Principle : Parkinson Law : 1984 : The Mythical Man-MonthHow to Solve It by George Polya : The Art of Computer Programming : The Elements of Programming Style : The Unix Hater’s Handbook : The Jargon file : The True Believer : Programming Pearls : The Good Soldier Svejk : The Power Elite

Most popular humor pages:

Manifest of the Softpanorama IT Slacker Society : Ten Commandments of the IT Slackers Society : Computer Humor Collection : BSD Logo Story : The Cuckoo's Egg : IT Slang : C++ Humor : ARE YOU A BBS ADDICT? : The Perl Purity Test : Object oriented programmers of all nations : Financial Humor : Financial Humor Bulletin, 2008 : Financial Humor Bulletin, 2010 : The Most Comprehensive Collection of Editor-related Humor : Programming Language Humor : Goldman Sachs related humor : Greenspan humor : C Humor : Scripting Humor : Real Programmers Humor : Web Humor : GPL-related Humor : OFM Humor : Politically Incorrect Humor : IDS Humor : "Linux Sucks" Humor : Russian Musical Humor : Best Russian Programmer Humor : Microsoft plans to buy Catholic Church : Richard Stallman Related Humor : Admin Humor : Perl-related Humor : Linus Torvalds Related humor : PseudoScience Related Humor : Networking Humor : Shell Humor : Financial Humor Bulletin, 2011 : Financial Humor Bulletin, 2012 : Financial Humor Bulletin, 2013 : Java Humor : Software Engineering Humor : Sun Solaris Related Humor : Education Humor : IBM Humor : Assembler-related Humor : VIM Humor : Computer Viruses Humor : Bright tomorrow is rescheduled to a day after tomorrow : Classic Computer Humor

The Last but not Least Technology is dominated by two types of people: those who understand what they do not manage and those who manage what they do not understand ~Archibald Putt. Ph.D


Copyright © 1996-2021 by Softpanorama Society. www.softpanorama.org was initially created as a service to the (now defunct) UN Sustainable Development Networking Programme (SDNP) without any remuneration. This document is an industrial compilation designed and created exclusively for educational use and is distributed under the Softpanorama Content License. Original materials copyright belong to respective owners. Quotes are made for educational purposes only in compliance with the fair use doctrine.

FAIR USE NOTICE This site contains copyrighted material the use of which has not always been specifically authorized by the copyright owner. We are making such material available to advance understanding of computer science, IT technology, economic, scientific, and social issues. We believe this constitutes a 'fair use' of any such copyrighted material as provided by section 107 of the US Copyright Law according to which such material can be distributed without profit exclusively for research and educational purposes.

This is a Spartan WHYFF (We Help You For Free) site written by people for whom English is not a native language. Grammar and spelling errors should be expected. The site contain some broken links as it develops like a living tree...

You can use PayPal to to buy a cup of coffee for authors of this site

Disclaimer:

The statements, views and opinions presented on this web page are those of the author (or referenced source) and are not endorsed by, nor do they necessarily reflect, the opinions of the Softpanorama society. We do not warrant the correctness of the information provided or its fitness for any purpose. The site uses AdSense so you need to be aware of Google privacy policy. You you do not want to be tracked by Google please disable Javascript for this site. This site is perfectly usable without Javascript.

Last modified: March, 12, 2019