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

Hi I'm sure a lot of you monks faced that question .
I would like to work with an orderd hash , to keep all the goodies of the hash ( direct access , defined .. ) but to determine the order of the entries .
do you know a clean way to do it or must I build an array and go over it with $i+=2 ( sort of hash simulation).
Thanks .
michaelg

Replies are listed 'Best First'.
Re: hash 2 array ?
by broquaint (Abbot) on Sep 15, 2003 at 11:25 UTC
    A nice and lazy approach (i.e the perl approach ;) would be to use Tie::IxHash, which will keep a tied hash in order for you e.g
    use Tie::IxHash; my %th; tie %th => "Tie::IxHash", qw/ foo bar baz quux /; print %th, $/; @th{qw/one three/} = qw/two four/; print %th, $/; __output__ foobarbazquux foobarbazquuxonetwothreefour
    And you'll see the contents of the hash have stayed nicely ordered, all thanks to Tie::IxHash.
    HTH

    _________
    broquaint

Re: hash 2 array ?
by Limbic~Region (Chancellor) on Sep 15, 2003 at 12:46 UTC
    michaelg.
    While Tie::IxHash preserves insertion order and provides a way to get sorted keys/values, the sort order is a simple textual compare only.

    For full control over the sort order, the ability to change it on the fly, and a bunch of other bells and whistles I would recommend Tie::Hash::Sorted.

    Cheers - L~R

Re: hash 2 array ?
by CombatSquirrel (Hermit) on Sep 15, 2003 at 11:23 UTC
    If your hash is static, how about
    $hash{$_} = { content => $hash{$_}, position => $i++ } for sort keys % +hash;
    Hope it works for you. Cheers,
    CombatSquirrel.
    Entropy is the tendency of everything going to hell.
      That would use a lot of memory. If I would need something like:
      $hash{$_} = { content => $hash{$_}, position => $i++ } for sort keys % +hash;
      I would do it like this:
      $hash{$_} = pack( 'N',$i++).$hash{$_} for sort keys %hash;
      in other words, prefix the ordinal number packed at the beginning of the string. Then, when you either need the linenumber and/or the original string, use unpack:
      my ($line,$string) = unpack( 'Na*',$hash{$key} );
      Liz
        Wouldn't this kill any chance of using leading digits in keys ({ '34' => 'thirty four' })? And take a significant runtime hit to pack and unpack accordingly?

        Tie::IxHash is already done. Does this not serve the purposes required?

        --
        [ e d @ h a l l e y . c c ]

Re: hash 2 array ?
by hardburn (Abbot) on Sep 15, 2003 at 14:12 UTC

    I would use Tie::IxHash or something like it, but here's a possibility not mentioned:

    For everything you insert into the hash, keep an array by its side. You can then use it in a hash slice. Example:

    my %hash; my @hash_array; $hash{key1} = 'value1'; push @hash_array, 'key1'; $hash{key2} = 'value2'; push @hash_array, 'key2'; . . . # Fetch the values. Notice that '%hash' has # an array sigil. my @values = @hash{@hash_array};

    ----
    I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
    -- Schemer

    Note: All code is untested, unless otherwise stated