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

I have a very small image viewer script which has a database full of id numbers from 1 - infinity. I delete a few of them from the database and my script knows how to ++ or -- to the next eligible entry in case there's a gap in ids.

I wrote the code quite a few years ago and now I'm thinking there's GOT to be a better way to do this. Here's a sample of my script finding the next available image

# determine next eligible image my $next_cnt = 0; while ($lowest) { $next_cnt++; if (exists $upload{$next_cnt}) { last; } } $next_cnt = $next_cnt + 2; # jump one ahead
I want to know if there's a way to determine what index a certain number is, inside my hash. Now I know indexes are used with arrays, but is there a similar way to do this in hashes if the keys are numbers?

Ie:

1,2,3,5,9,10
We are on image 5 and want to find out what the previous and next number in sequence would be..
my $prev = $db{$picid}..
There just has to be a way to automatically determine, in a sorted hash, what the previous and next items would be. Right?

Replies are listed 'Best First'.
Re: how to check which index $x is in an hash
by GrandFather (Saint) on May 21, 2007 at 21:40 UTC

    If you use the lookup a lot then it's worth making a lookup table. Consider

    use strict; use warnings; my %upload = (1 => 'one', 2 => 'two', 3 => 'three', 5 => 'five', 9 => +'nine', 10 => 'ten'); my @keys = sort {$a <=> $b} keys %upload; my %lookup = map { $keys[$_] => { prev => $_ ? $keys[$_ - 1] : undef, next => $_ != $#keys ? $keys[$_ + 1] : undef, } } 0 .. $#keys; for my $key (1, 5, 10) { if (defined $lookup{$key}{next}) { print "$lookup{$key}{next} follows $key\n"; } else { print "$key is the last item\n"; } if (defined $lookup{$key}{prev}) { print "$lookup{$key}{prev} precedes $key\n"; } else { print "$key is the first item\n"; } }

    Prints:

    2 follows 1 1 is the first item 9 follows 5 3 precedes 5 10 is the last item 9 precedes 10

    The lookup creation is a little more succinct if you make use of autovivification:

    my %lookup = map {$keys[$_] => {prev => $keys[$_ - 1], next => $keys[$ +_ + 1]}} 0 .. $#keys;

    Update: see johngg's reply below!


    DWIM is Perl's answer to Gödel
      I think your more succinct version will have a problem with the first key. This is because $_ going into the map is going to be 0 thus prev => $keys[0 - 1] will result in prev => 10. At the other end, I think that next => $keys[$#keys + 1] will do the right thing as pointing off the end of the array should result in undef.

      Cheers,

      JohnGG

        Argh, you are quite right! I "checked" it, honest, I just didn't notice the line that says "10 precedes 1"!


        DWIM is Perl's answer to Gödel
Re: how to check which index $x is in an hash
by shmem (Chancellor) on May 21, 2007 at 21:31 UTC
    my @sorted_indices = sort {$a <=> $b} keys %upload;

    Then iterate over @sorted_indices.

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
      Right, that's my question though. I have an array of hash keys. If I have an array with 1,2,5,7,10, how do I determine what index 5 is? I know it's 2, but how can the script know?
        how can the script know?

        The script doesn't know anything, ever. It's you who knows, or doesn't, and the script reflects that knowledge.

        If I have an array with 1,2,5,7,10, how do I determine what index 5 is? I know it's 2

        You make another hash, keyed with the contents of your array slots, whose values are their indices:

        # (merging previous post) my @sorted_indices = sort {$a <=> $b} keys %upload; my %lookup_hash; @lookup_hash{@sorted_indices} = 0 .. $#sorted_indices;

        Now you lookup e.g. 5 in %lookup_hash:

        my $i = $lookup_hash{5}; print $x,"\n"; # prints 2 # get the next element from the hash my $next = $sorted_indices[$x + 1]; # $next holds 7 # get your image my $image = $uploads{$next};

        --shmem

        _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                      /\_¯/(q    /
        ----------------------------  \__(m.====·.(_("always off the crowd"))."·
        ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
Re: how to check which index $x is in an hash
by Tux (Canon) on May 21, 2007 at 21:31 UTC
    like in
    my @image_ids = sort { $a <=> $b } keys %db;
    ?

    Enjoy, Have FUN! H.Merijn
Re: how to check which index $x is in an hash
by Anonymous Monk on May 21, 2007 at 21:28 UTC
    Or heck, I could make an array full of hash keys. Is there a way to detect previous/next index in arrays?