tadman has asked for the wisdom of the Perl Monks concerning the following question: (hashes)

How do I select a random key from a hash?

Originally posted as a Categorized Question.

  • Comment on How do I select a random key from a hash?

Replies are listed 'Best First'.
Re: How do I select a random key from a hash?
by mirod (Canon) on Feb 05, 2001 at 20:57 UTC

    The brute force solution:

    /bin/perl -w use strict; my %h=( k1 => "v1", k2 => "v2", k3 => "v3"); my @keys= keys %h; my $k= $keys[int rand( @keys)]; print "random key: $k\n";'

    If you want to do this on a huge hash and you want to do lots of random access and updates then you should look at Building a Better Hash, a pretty clever way to solve this problem.

Re: How do I select a random key from a hash?
by arhuman (Vicar) on Feb 05, 2001 at 21:43 UTC
    What's wrong with this ?:
    $lh=scalar keys %h; print ((keys %h)[int rand($lh)]);
    [Q&A Editor- Changed '(split "/",scalar %h)[0]' to "scalar keys %h" as noted by chipmunk.]
      In a scalar context, %h returns a string consisting of the number of buckets used, a slash, and the number of buckets allocated. You could have a hash with 1000 keys and only 16 buckets. Thus, your "random key" is limited to one of the first few keys in the hash.

      Try $lh = scalar keys %h; instead.

Re: How do I select a random key from a hash?
by MrNobo1024 (Hermit) on Mar 25, 2001 at 00:48 UTC
    ((keys %hash)[int rand keys %hash]) You don't need scalar() because rand() automatically converts its argument to a scalar.
      You also don't need int because indexing automatically int's it. {grin}

      But you are computing the keys twice, and that's expensive for large hashes. Perhaps this instead:

      do { my @k = keys %hash; $k[rand @k] }

      -- Randal L. Schwartz, Perl hacker

        scalar keys %hash doesn't actually compute the keys (except for tied hashes).
Re: How do I select a random key from a hash?
by arhuman (Vicar) on Feb 05, 2001 at 21:58 UTC
    $lh=(split "/",scalar keys %h)[0]; print ((keys %h)[int rand($lh)]);
    [Q&A Editor- Changed "scalar %h" to "scalar keys %h" as noted by chipmunk.]

    Originally posted as a Categorized Answer.