in reply to rebuilding hashes

Once the '2' element is deleted, you go through the hash with a counter and reassign (2 => 'three', 3 => 'four' ). The '4' element remains, as well.

I'm suspicious of the kind of sorting you do. What happens when you have 42 elements? Your sort will go 0,1,10,11,12... which I'm not convinced you will expect.

Why not use aa array for this? You can delete elements with splice and the renumbering will be automatic.

After Compline,
Zaxo

Replies are listed 'Best First'.
Re: Re: rebuilding hashes
by coldfingertips (Pilgrim) on Feb 02, 2004 at 20:14 UTC
    I still don't quite understand why 'four' is being repeated. When I delete {2} the key and value of 3/three should be removed and a print with the result:
    0 ==== zero 1 ==== one 2 ==== three 3 ==== four
    I wrote a note above that goes over why I'm not using an array. This hash in reality isn't being used, this is a test script I setup to see if it would work. I'm actually tying this hash to SDBM and sorting by numbered keys has never been a problem for me using for (grep defined($_), (sort { $a <=> $b } keys %code).

    The reason I need to rebuild the hash is because in the admin panel, when they remove a key/value, the user is returned to a menu with back and foward buttons that lets them scroll the data. For the forward button, I increment the key value by one, and the opposite for the back button. BUT, if we have keys 1, 2, 3, 4, 5 and they remove 3, the navigation buttons crash between two and four because it loads 3 which doesn't exist.

      I still don't quite understand why 'four' is being repeated.

      It's because you still have a key '4' with a value of "four" that you didn't remove from the hash. Perhaps an illustration. Your hash just after you delete the entry keyed by '2':

      0 === zero 1 === one 3 === three 4 === four

      Then you loop over the keys creating new entries. After the first iteration of the loop your hash looks like this:

      0 === zero # this one reassigned 1 === one 3 === three 4 === four

      Second iteration:

      0 === zero 1 === one # this one reassigned 3 === three 4 === four

      Third iteration:

      0 === zero 1 === one 2 === three # this one created 3 === three 4 === four

      Fourth iteration:

      0 === zero 1 === one 2 === three 3 === four # this one reassigned 4 === four

      See?

      I still don't quite understand why 'four' is being repeated.
      Abigail-II actually answered this question for you:
      Third, it's showing four twice because you never delete the highest number when re-assigning the numbers.
      I hate to push the issue, but even with your further description, an array sounds like a more appropriate (and less error-prone) data-structure for this problem. Matter of fact you wouldn't even have this problem at all if you used a tied-array for this. It seems to me that your index-keys aren't even really nessecary at all, they are just indecies to the natural order of your list.

      With an array, your HTML-display code could just use a "counter" variable for your page number display rather than the hash-key. Something like this.

      foreach my $page_num (1 .. scalar @pages) { print "<A HREF='script.pl?page=$page_num'>page $page_num</A>"; }
      Then your CGI code would just use the value of "page" as an index to your array, and it will always be guarenteed to be there (assuming they don't reach over the bounds of your array in some way, but thats another problem).

      If this weren't a tied hash i might recommend re-building it from a totally empty (new) hash then you wouldn't need to deal with this problem at all, but i assume the performance penalty on that would be painful.

      -stvn
      As Abigail-II said, you never do anything that would delete the {4} key. Assigning its value to the {3} key doesn't affect {4}.

      A crude way to fix it: After your reassignment loop, delete keys until there are only 1 + (original)$num.

      my $to_delete = keys(%hash) - $num+1; while ($to_delete) { --$to_delete if defined delete $hash{++$num}; }