http://www.perlmonks.org?node_id=140064

an_ordinary_man has asked for the wisdom of the Perl Monks concerning the following question:

%array = ( "100", "Green", "200", "Orange"); while (($key, $value) = each(%array)) { print("$key = $value\n"); }
Acc. to the functionality of above code, each() function used on associative array, This program should print the following:
100 = Green 200 = Orange
But on running it on my machine, it returns:
200 = Orange 100 = Green
On adding more key, value pairs it gives different results which I cannot find a pattern for. This same code when run on other machine with different perl running on it works. I really need to know why this does not come in the order as it is in the array.

Replies are listed 'Best First'.
Re (tilly) 1: each() function used in associative arrays gives incorrect unordered output.
by tilly (Archbishop) on Jan 19, 2002 at 13:02 UTC
    According to each (and also to the more accurate documentation you can get with perldoc -f each) your notion of "should" is incorrect.

    Generally things should not work contrary to the documentation. For more on why there is no apparent order, see Re (tilly) 4: Flip Flop III - Musical Buckets.

    In your case if you want to get the key/value pairs out in a particular order, it is probably best to keep the keys in an array, iterate over the array and extract the values with a hash lookup.

Re: each() function used in associative arrays gives incorrect unordered output.
by rob_au (Abbot) on Jan 19, 2002 at 13:04 UTC
    Hash structures by their nature are unordered lists of scalars - There is no intrinsic order to the index keys which are returned via keys or each. It is discussed in the perldata man page that while a hash may be initialised in a particular order it is no guarentee that iteration of the hash index returns elements in this order - This is also discussed in the perlfunc:keys man page.

     

    perl -e 's&&rob@cowsnet.com.au&&&split/[@.]/&&s&.com.&_&&&print'

Re: each() function used in associative arrays gives incorrect unordered output.
by uwevoelker (Pilgrim) on Jan 19, 2002 at 13:30 UTC
    If you want ordered output you could use
    foreach my $key (sort(keys %array)) { print "$key = $array{$key}\n"; }
Re: each() function used in associative arrays gives incorrect unordered output.
by Juerd (Abbot) on Jan 19, 2002 at 20:03 UTC
    Hashes aren't stored in the order they were defined. They're stored in whatever order perl thinks is efficient. If you had read ANY documentation on hashes, you would know that. Yes, each() gives unordered output (actually, it is ordered in a way, but the order is a bit hard to predict), but that's not incorrect. Your assumption that perl always DWYM is incorrect.

    (Update (200201191751+0100) Removed offensive text.
    Here's a list of documents that would have helped you out:
    • perldoc -q order gives exactly one hit, from perlman:perlfaq4:
      How can I make my hash remember the order I put elements into it?
      Use the Tie::IxHash from CPAN.
    • perldata is the place to look for information about data types. A quick search for the word "order" here gives the following paragraph:
      Note that just because a hash is initialized in that order doesn't mean that it comes out in that order. See "sort" in perlfunc for examples of how to arrange for an output ordering.
    • You used each, so I'll look up that documentation as well (in perlfunc):
      Entries are returned in an apparently random order. The actual random order is subject to change in future versions of perl, but it is guaranteed to be in the same order as either the "keys" or "values" function would produce on the same (unmodified) hash.
      Perlfunc has similar warnings in the keys and values department :)
    As you can see, there's plenty of documentation on this subject. You just didn't read it. Next time, please RTFriendlyM before asking a question that has already been answered in great detail.

    BTW, you said "... in the order as it is in the array", but didn't use any array. (The thing right of the = in your hash assignment is called a list - an array is mutable, a list is not.)

    2;0 juerd@ouranos:~$ perl -e'undef christmas' Segmentation fault 2;139 juerd@ouranos:~$

Re: each() function used in associative arrays gives incorrect unordered output.
by japhy (Canon) on Jan 19, 2002 at 21:19 UTC
    This was also posted to the Perl5-Porters list, where it was answered by a handful of people (myself included), and you were given a possible course of action (Tie::IxHash).

    _____________________________________________________
    Jeff[japhy]Pinyan: Perl, regex, and perl hacker.
    s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

Re: each() function used in associative arrays gives incorrect unordered output.
by trs80 (Priest) on Jan 19, 2002 at 21:33 UTC
    I think the issue is in the last statement made in the post.
    In the code sample provided an array is NOT created at
    any point. The hash ( associative array ) is named array, but
    it is a hash. It might be simply a misunderstanding that
    the code sample isn't creating an array. In looking at it
    from this angle I can see where someone might expect the
    the results to be in the same order. That is thinking that
    an array has been created because we didn't use the more
    traditional '=>' creation method.
      I don't know if "array" in "associative array" implies order, but the name "associative array" was used in perl 4. Ever since the introduction of perl 5, the thing's called "hash". (Correct me if I'm wrong)

      2;0 juerd@ouranos:~$ perl -e'undef christmas' Segmentation fault 2;139 juerd@ouranos:~$