Ordered hashes

Discussion in 'Perl Misc' started by January Weiner, Mar 1, 2006.

  1. Hi,

    I run into this basic problem now and then.

    Hashes allow you to access an element by a key. However, hashes are not
    ordered. Take the following example: I have a hash containing a menu
    structure:

    my %menu = ( -file => [ "new", "open", "save" ],
    -analize => [ "count", "add", "subtract" ],
    -help => [ "yelp", "cry", "bang your head on the wall" ],
    ) ;

    Now I have some arbitrary function that should display this menu. However,
    the order should be preserved, and there is no way we could order it
    automatically (e.g. alphabetically). I see two solutions:

    1) create a menu index:

    my @menu_idx = ( "-file", "-analize", "-help" ) ;

    for(@menu_idx) {
    do_something($menu{$_}) ;
    }

    2) pretend %menu is an array:

    my @menu = ( "-file", [ "new", "open", "save" ],
    "-analize", [ "count", "add", "subtract" ],
    "-help", [ "yelp", "cry", "bang your head on the wall" ],
    ) ;

    my %menu_hash = @menu ;

    for($i = 0 ; $i < scalar(@menu) ; $i += 2) {
    do_something($menu_hash{$menu[$i]}) ;
    }

    Neither seems to be satisfactory. Are there better ways of dealing with
    this problem?

    j.

    --
     
    January Weiner, Mar 1, 2006
    #1
    1. Advertising

  2. January Weiner

    Ch Lamprecht Guest

    January Weiner wrote:
    > Hi,
    >
    > I run into this basic problem now and then.
    >
    > Hashes allow you to access an element by a key. However, hashes are not
    > ordered. Take the following example: I have a hash containing a menu
    > structure:
    >
    > my %menu = ( -file => [ "new", "open", "save" ],
    > -analize => [ "count", "add", "subtract" ],
    > -help => [ "yelp", "cry", "bang your head on the wall" ],
    > ) ;
    >
    > Now I have some arbitrary function that should display this menu. However,
    > the order should be preserved, and there is no way we could order it
    > automatically (e.g. alphabetically). I see two solutions:
    >


    >
    > Neither seems to be satisfactory. Are there better ways of dealing with
    > this problem?
    >
    > j.
    >

    Hi,
    perldoc -q order hash

    HTH, Chris


    --

    perl -e "print scalar reverse q//"
     
    Ch Lamprecht, Mar 1, 2006
    #2
    1. Advertising

  3. January Weiner

    Anno Siegel Guest

    January Weiner <> wrote in comp.lang.perl.misc:
    > Hi,
    >
    > I run into this basic problem now and then.
    >
    > Hashes allow you to access an element by a key. However, hashes are not
    > ordered. Take the following example: I have a hash containing a menu
    > structure:
    >
    > my %menu = ( -file => [ "new", "open", "save" ],
    > -analize => [ "count", "add", "subtract" ],
    > -help => [ "yelp", "cry", "bang your head on the wall" ],
    > ) ;
    >
    > Now I have some arbitrary function that should display this menu. However,
    > the order should be preserved,


    There are modules that give you hashes that *do* preserve order.
    Tie::IxHash is one.

    > and there is no way we could order it
    > automatically (e.g. alphabetically). I see two solutions:


    Why not? A typical menu doesn't have a million entries. It is usually
    no problem to sort the entries alphabetically by their hash keys each
    time they are displayed.

    > 1) create a menu index:
    >
    > my @menu_idx = ( "-file", "-analize", "-help" ) ;
    >
    > for(@menu_idx) {
    > do_something($menu{$_}) ;
    > }


    That is probably what order-preserving hashes do under the hood.

    > 2) pretend %menu is an array:


    Pretend? You have changed the representation, the menu now *is* an
    array.

    > my @menu = ( "-file", [ "new", "open", "save" ],
    > "-analize", [ "count", "add", "subtract" ],
    > "-help", [ "yelp", "cry", "bang your head on the wall" ],
    > ) ;
    >
    > my %menu_hash = @menu ;
    >
    > for($i = 0 ; $i < scalar(@menu) ; $i += 2) {
    > do_something($menu_hash{$menu[$i]}) ;
    > }
    >
    > Neither seems to be satisfactory. Are there better ways of dealing with
    > this problem?


    I'd probably use another variant. Represent the menu as a list of
    pairs:

    my @menu = (
    [ -file => [ qw( new open save)]],
    [ -analyze => [ qw( count add subtract)]],
    [ -help => [ qw( yelp cry), 'bang your head on the wall']],
    );

    Then you can loop over @menu in the given order (like an array) and
    access the name and the choices individually, like with a hash.

    for ( @menu ) {
    print "$_->[ 0]: ", join( ', ', @{ $_->[ 1] }), "\n";
    }

    Anno
    --
    If you want to post a followup via groups.google.com, don't use
    the broken "Reply" link at the bottom of the article. Click on
    "show options" at the top of the article, then click on the
    "Reply" at the bottom of the article headers.
     
    Anno Siegel, Mar 1, 2006
    #3
  4. January Weiner

    Guest

    January Weiner <> wrote:

    > Now I have some arbitrary function that should display this menu.
    > However, the order should be preserved, and there is no way we could
    > order it automatically (e.g. alphabetically). I see two solutions:
    >
    > 1) create a menu index:
    >
    > my @menu_idx = ( "-file", "-analize", "-help" ) ;
    >
    > for(@menu_idx) {
    > do_something($menu{$_}) ;
    > }


    # how about a hash slice?
    do_somehitng($_) foreach @menu{@menu_idx};

    >
    > 2) pretend %menu is an array:
    >
    > my @menu = ( "-file", [ "new", "open", "save" ],
    > "-analize", [ "count", "add", "subtract" ],
    > "-help", [ "yelp", "cry", "bang your head on the wall" ],
    > ) ;
    >
    > my %menu_hash = @menu ;
    >
    > for($i = 0 ; $i < scalar(@menu) ; $i += 2) {
    > do_something($menu_hash{$menu[$i]}) ;
    > }
    >
    > Neither seems to be satisfactory. Are there better ways of dealing with
    > this problem?


    How to deal with the problem depends on what specifically you find
    unsatisfactory about the solutions you already have.

    Xho

    --
    -------------------- http://NewsReader.Com/ --------------------
    Usenet Newsgroup Service $9.95/Month 30GB
     
    , Mar 1, 2006
    #4
  5. Anno Siegel <-berlin.de> wrote:
    > There are modules that give you hashes that *do* preserve order.
    > Tie::IxHash is one.


    Right, thanks -- that is the solution I sought.

    > Why not? A typical menu doesn't have a million entries. It is usually
    > no problem to sort the entries alphabetically by their hash keys each
    > time they are displayed.


    Either you have Menus not sorted logically, or you have to remember that
    "File" is "aFile" and "Help" is "zHelp". Anyway, menus were just an
    example I came up with.

    > Pretend? You have changed the representation, the menu now *is* an
    > array.


    Yes, formally speaking it is, but practically speaking I do not use it as
    one, correct? Anyway, it was a metaphor.

    > I'd probably use another variant. Represent the menu as a list of
    > pairs:


    > my @menu = (
    > [ -file => [ qw( new open save)]],
    > [ -analyze => [ qw( count add subtract)]],
    > [ -help => [ qw( yelp cry), 'bang your head on the wall']],
    > );


    > Then you can loop over @menu in the given order (like an array) and
    > access the name and the choices individually, like with a hash.


    I think I'm lost. How can I access the elements of @menu above
    individually like in a hash? I have to access the elements of @menu by
    their index, and cannot do so by the key (or you mean the elements of the
    anonymous arrays within?).

    Cheers, and thanks!

    j.

    --
     
    January Weiner, Mar 1, 2006
    #5
  6. Ch Lamprecht <> wrote:
    > Hi,
    > perldoc -q order hash


    Thanks!!

    j.

    --
     
    January Weiner, Mar 1, 2006
    #6
  7. January Weiner

    Anno Siegel Guest

    January Weiner <> wrote in comp.lang.perl.misc:
    > Anno Siegel <-berlin.de> wrote:
    > > There are modules that give you hashes that *do* preserve order.
    > > Tie::IxHash is one.

    >
    > Right, thanks -- that is the solution I sought.
    >
    > > Why not? A typical menu doesn't have a million entries. It is usually
    > > no problem to sort the entries alphabetically by their hash keys each
    > > time they are displayed.

    >
    > Either you have Menus not sorted logically, or you have to remember that
    > "File" is "aFile" and "Help" is "zHelp". Anyway, menus were just an
    > example I came up with.


    Ah, okay. You could sort them alphabetically, but that isn't the
    order you want.

    > > Pretend? You have changed the representation, the menu now *is* an
    > > array.

    >
    > Yes, formally speaking it is, but practically speaking I do not use it as
    > one, correct? Anyway, it was a metaphor.
    >
    > > I'd probably use another variant. Represent the menu as a list of
    > > pairs:

    >
    > > my @menu = (
    > > [ -file => [ qw( new open save)]],
    > > [ -analyze => [ qw( count add subtract)]],
    > > [ -help => [ qw( yelp cry), 'bang your head on the wall']],
    > > );

    >
    > > Then you can loop over @menu in the given order (like an array) and
    > > access the name and the choices individually, like with a hash.

    >
    > I think I'm lost. How can I access the elements of @menu above
    > individually like in a hash?


    You can't, but for what my example code does you don't need to.

    > I have to access the elements of @menu by
    > their index, and cannot do so by the key (or you mean the elements of the
    > anonymous arrays within?).


    Basically you need a hash *and* an array for that. You can do that
    yourself, or use one of the ordered-hash modules that hide the
    implementation.

    Anno
    --
    If you want to post a followup via groups.google.com, don't use
    the broken "Reply" link at the bottom of the article. Click on
    "show options" at the top of the article, then click on the
    "Reply" at the bottom of the article headers.
     
    Anno Siegel, Mar 2, 2006
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ben Holness

    Hashes of Hashes via subs

    Ben Holness, Oct 5, 2003, in forum: Perl
    Replies:
    8
    Views:
    593
    Ben Holness
    Oct 8, 2003
  2. Steven Arnold

    using hashes as keys in hashes

    Steven Arnold, Nov 23, 2005, in forum: Ruby
    Replies:
    3
    Views:
    186
    Mauricio Fernández
    Nov 23, 2005
  3. Tim O'Donovan

    Hash of hashes, of hashes, of arrays of hashes

    Tim O'Donovan, Oct 27, 2005, in forum: Perl Misc
    Replies:
    5
    Views:
    237
  4. Julian

    ordered hashes

    Julian, Dec 9, 2008, in forum: Perl Misc
    Replies:
    13
    Views:
    156
  5. DL

    Ordered list inside ordered list

    DL, Nov 9, 2009, in forum: Javascript
    Replies:
    6
    Views:
    356
    Dr J R Stockton
    Nov 21, 2009
Loading...

Share This Page