From: Tom Christiansen <tchrist@convex.COM>
Subject: Re: What's the best idiom for storing keyed records?
Originator: tchrist@pixel.convex.com
Date: Wed, 19 Aug 1992 00:45:16 GMT
Reply-To: tchrist@convex.COM (Tom Christiansen)
Organization: CONVEX Realtime Development, Colorado Springs, CO
X-Disclaimer: This message was written by a user at CONVEX Computer
              Corp. The opinions expressed are those of the user and
              not necessarily those of CONVEX.

From the keyboard of tmhoff@oogoody.Corp.Sun.COM:
:
:How in the heck do I store a list in an associative array?
:I want to store a datbase record in an array, but it seems
:an associative array only stores strings. This must be
:a common problem. I would like to see how others have solved it.
:
:I can think of creating an array for every record field, but this
:seems crude.

I know, I've been  remiss about posting the FAQ, but #17 discusses
this.  You can

    a) store the array as "@array" and resplit it each time.
    b) store the array as its name, "array", and eval "\@$name"
       to get at it.
    c) store the array as a pointer to its stab entry, *array,
	and local(*array) = $table{$entry} to get at it.

--tom

17) How can I make an array of arrays or other recursive data types?

    Remember that Perl isn't about nested data structures, but rather flat
    ones, so if you're trying to do this, you may be going about it the
    wrong way.  You might try parallel arrays with common subscripts.

    But if you're bound and determined, you can use the multi-dimensional
    array emulation of $a{'x','y','z'}, or you can make an array of names
    of arrays and eval it.

    For example, if @name contains a list of names of arrays, you can 
    get at a the j-th element of the i-th array like so:

	$ary = $name[$i];
	$val = eval "\$$ary[$j]";

    or in one line

	$val = eval "\$$name[$i][\$j]";

    You could also use the type-globbing syntax to make an array of *name
    values, which will be more efficient than eval.  Here @name hold
    a list of pointers, which we'll have to dereference through a temporary
    variable.

    For example:

	{ local(*ary) = $name[$i]; $val = $ary[$j]; }

    In fact, you can use this method to make arbitrarily nested data
    structures.  You really have to want to do this kind of thing
    badly to go this far, however, as it is notationally cumbersome.

    Let's assume you just simply *have* to have an array of arrays of
    arrays.  What you do is make an array of pointers to arrays of
    pointers, where pointers are *name values described above.  You
    initialize the outermost array normally, and then you build up your
    pointers from there.  For example:

	@w = ( 'ww' .. 'xx' );
	@x = ( 'xx' .. 'yy' );
	@y = ( 'yy' .. 'zz' );
	@z = ( 'zz' .. 'zzz' );

	@ww = reverse @w;
	@xx = reverse @x;
	@yy = reverse @y;
	@zz = reverse @z;

    Now make a couple of array of pointers to these:

	@A = ( *w, *x, *y, *z );
	@B = ( *ww, *xx, *yy, *zz );

    And finally make an array of pointers to these arrays:

	@AAA = ( *A, *B );

    To access an element, such as AAA[i][j][k], you must do this:

	local(*foo) = $AAA[$i];
	local(*bar) = $foo[$j];
	$answer = $bar[$k];

    Similar manipulations on associative arrays are also feasible.

    You could take a look at recurse.pl package posted by Felix Lee
    <flee@cs.psu.edu>, which lets you simulate vectors and tables (lists and
    associative arrays) by using type glob references and some pretty serious
    wizardry.

    In C, you're used to creating recursive datatypes for operations
    like recursive decent parsing or tree traversal.  In Perl, these
    algorithms are best implemented using associative arrays.  Take an
    array called %parent, and build up pointers such that $parent{$person}
    is the name of that person's parent.  Make sure you remember that
    $parent{'adam'} is 'adam'. :-) With a little care, this approach can
    be used to implement general graph traversal algorithms as well.


-- 
    Tom Christiansen      tchrist@convex.com      convex!tchrist

    signal(i, SIG_DFL); /* crunch, crunch, crunch */
        --Larry Wall in doarg.c from the perl source code