in reply to Re: Which, if any, is faster?
in thread Which, if any, is faster?

I don't know if I'd agree with ignoring potential problems. I think they should at least question (like they are) the possible impact of using an array vs a hash. My recommendation would be to write a simple loop that runs through what ever process you are trying to run using each, and time how long it takes to run through 100, 1000, or 1000000 iterations to get an accurate idea of which is better suited for your needs. Ultimately you will have people arguing for both sides but only through testing are you going to find out which is more efficient.

Replies are listed 'Best First'.
Re^3: Which, if any, is faster?
by rvosa (Curate) on Jun 01, 2005 at 08:55 UTC
    Here's a little bit of background: I have an object Node that is, at its core, now a blessed anonymous hash. The hash contains keys first_daughter, last_daughter, next_sister, previous_sister and parent, the values of which are references pointing to other such nodes. (The nodes are contained within a Tree object, which is a blessed anonymous array.) I've found that with large-ish trees - my testcase has 427 nodes - traversals, for example recursively going first_daughter->next_sister from root to tips where on every step the reference is retrieved through an accessor method, becomes somewhat slow.

    So the question is whether it would help to have the references stored in an anonymous array? As you suggest, I'll probably try it out anyway, but I was wondering if anyone has any experience with this kind of structure & method and whether they can say it is or isn't worth the trouble. A hash is certainly easier to remember than keeping track of the array indices for the various getters & setters.

      One way of addressing the array indices problem is to declare constants for your array elements.

      use constant { SELF => 0, CODE_TO_RUN => 1, FIRST_DAUGHTER => 0, LAST_DAUGHTER => 1, NEXT_SISTER => 2, PREVIOUS_SISTER => 3, PARENT => 4, }; ## then in your methods sub traverse { if( $_[SELF][FIRST_DAUGHTER] ) { traverse( $_[SELF][FIRST_DAUGHTER], $_[CODE_TO_RUN] ); } elsif( $_[SELF][NEXT_SISTER] ) { traverse( $_[SELF][NEXT_SISTER], $_[CODE_TO_RUN] ); elsif( ... ) ...; } return; }

      Constants created this way get turned into constant subroutines which then get optimised away leaving just the value behind which makes for an efficient way of indexing arrays symbolically.

      And by using the aliasing of @_ directly, rather than shifting or copying values into lexicals, you save a little more time and space.

      With well chosen constant names, it is also eminently readable, even if the uppercase tends to look a little strange at first.

      For those methods (like traverse()) that lend themselves to tail recursion, you can take this further:

      sub traverse { return unless defined $_[SELF]; $_[CODE_TO_RUN]->( ... ); $_[SELF] = $_[SELF][FIRST_DAUGHTER] || $_[SELF][NEXT_SISTER] || undef; goto &traverse; }

      But some might consider that a step too far.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
      "Science is about questioning the status quo. Questioning authority".
      The "good enough" maybe good enough for the now, and perfection maybe unobtainable, but that should not preclude us from striving for perfection, when time, circumstance or desire allow.