[comp.lang.perl] assoc array

sylvank@syma.sussex.ac.uk (Sylvan Katz) (05/14/91)

I have an application which requires that I initialize an associative
array for counting purposes:

EG:

	%matrix = ('A',0,'AA',0,'B',0,'BB',0);

However, when I examine the order of the array elements with

	foreach $key (keys %matrix) { print "$key ";}

I find order is

	BB A B AA 

Any suggestions on how I can PRESERVE the initial order (it is
imperative for my applications) ?

Sylvan
sylvank@syma.sussex.ac.uk

tchrist@convex.COM (Tom Christiansen) (05/18/91)

From the keyboard of sylvank@syma.sussex.ac.uk (Sylvan Katz):
:I have an application which requires that I initialize an associative
:array for counting purposes:
:
:EG:
:
:	%matrix = ('A',0,'AA',0,'B',0,'BB',0);
:
:However, when I examine the order of the array elements with
:
:	foreach $key (keys %matrix) { print "$key ";}
:
:I find order is
:
:	BB A B AA 
:
:Any suggestions on how I can PRESERVE the initial order (it is
:imperative for my applications) ?

If you're not adding any elements to the array, you could do this:

    @keys = ('A','AA','B','BB');
    @matrix{@keys} = ();

or, if having the values initialized to undef bothers you:

    @matrix{@keys} = (0) x @keys;

Then process them with:

    for $key (@keys) {
	print "key ", $key, " is ", $matrix{$key}, "\n";
    } 

Other more baroque ideas come to mind, like this one, which might
perhaps be of use to you if you have some other criteria I'm
not aware of:

    %order = (); $order = 0;
    for (@keys) { $order{$_} = $order++; } 
    # later on...
    sub by_order { $order{$a} <=> $order{$b}; }
    for (sort by_order keys %matrix) {
	print "key ", $key, " is ", $matrix{$key}, "\n";
    } 

In short, it all else fails, call an auxiliary function to help you
get the ordering down.


--tom
--
Tom Christiansen		tchrist@convex.com	convex!tchrist
		"So much mail, so little time." 

roger@mav.com (Roger Droz) (05/25/91)

In article <1991May18.160757.15011@convex.com> tchrist@convex.COM (Tom Christiansen) writes:
>From the keyboard of sylvank@syma.sussex.ac.uk (Sylvan Katz):
>:I have an application which requires that I initialize an associative
>:array for counting purposes:
>:
>:EG:
>:
>:	%matrix = ('A',0,'AA',0,'B',0,'BB',0);
>:
>:However, when I examine the order of the array elements with
>:
>:	foreach $key (keys %matrix) { print "$key ";}
>:
>:I find order is
>:
>:	BB A B AA 
>:
>:Any suggestions on how I can PRESERVE the initial order (it is
>:imperative for my applications) ?
>
>If you're not adding any elements to the array, you could do this:
>
>    @keys = ('A','AA','B','BB');

Tom is right about using a second array to preserve order.  Perl doesn't
preserve order in associative arrays by itself.

Unless you explicitly want to keep track of things that occur zero
times, there is no reason to initialize the associative array.

	$matrix{$thing}++

is a fine way to count aribrary things.

If you want to count a specific list of things that may occur zero or
more times, I agree with Tom:

>    @matrix{@keys} = (0) x @keys;
>
>Then process them with:
>
>    for $key (@keys) {
>	print "key ", $key, " is ", $matrix{$key}, "\n";
>    } 
>

Perl will happily count things outside your list of keys without
complaint, so you may want to add a sanity check as you count your
input data:

	unless (defined $matrix{$thing}++) {
	    $none_of_above++;
	}
____________
               Roger Droz                  Domain: roger@mav.COM           
()       ()    Maverick International      UUCP: uw-beaver!gtisqr!roger
 (_______)     Mukilteo, WA 
  (     )      
   |   |       Disclaimer: "We're all mavericks here: 
   |   |                    Each of us has our own opinions,
   (___)                    and the company has yet different ones!"