Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do Perl FIRSTKEY and NEXTKEY work

Tags:

perl

Tie::Hash has these:

sub FIRSTKEY { my $a = scalar keys %{$_[0]}; each %{$_[0]} }
sub NEXTKEY  { each %{$_[0]} }

NEXTKEY takes two arguments, one of which is the last key but that arg is never referenced?

The various Tie docs don't shed any light on this other than this in perltie:

my $a = keys %{$self->{LIST}};      # reset each() iterator

looking at the doc for each doesn't add to this.

What's going on?

like image 827
mmccoo Avatar asked Jun 09 '10 23:06

mmccoo


People also ask

How does Perl hash work?

A hash is a set of key/value pairs. Hash variables are preceded by a percent (%) sign. To refer to a single element of a hash, you will use the hash variable name preceded by a "$" sign and followed by the "key" associated with the value in curly brackets..

What is Perl hash?

A hash is a set of key-value pairs. Perl stores elements of a hash such that it searches for the values based on its keys. Hash variables start with a '%' sign. Perl requires the keys of a hash to be strings, whereas the values can be any scalars. These values can either be a number, string or reference.


1 Answers

You only need to worry about the second argument to NEXTKEY if you care about which key was accessed last. By default, hashes don't care about the order, so it is not used.

As for the second part, the keys function in scalar context returns the number of items in the hash. Any call to keys resets the iterator used by keys and each because it exhausts the iterator.

A call to keys is really a call to FIRSTKEY and calls to NEXTKEY until there are no more items left in that haven't been returned.

A call to each is a call to FIRSTKEY (if FIRSTKEY hasn't been called yet) or a call to NEXTKEY (if FIRSTKEY has been called).

#!/usr/bin/perl

use strict;
use warnings;

my $i = 0;
tie my %h, "HASH::Sorted", map { $_ => $i++ } "a" .. "g";

for my $key (keys %h) {
    print "$key => $h{$key}\n";
}
print "\n";

my $first = each %h;
print "first $first => $h{$first}\n";

my ($second_key, $second_value) = each %h;
print "second $second_key => $second_value\n";

print "\nall of them again:\n";
for my $key (keys %h) {
    print "$key => $h{$key}\n";
}

package HASH::Sorted;

sub TIEHASH {
    my $class = shift;

    return bless { _hash => { @_ } }, $class;
}

sub FETCH {
    my ($self, $key) = @_;

    return $self->{_hash}{$key};
}

sub STORE {
    my ($self, $key, $value) = @_;

    return $self->{_hash}{$key} = $value;
}

sub DELETE {
    my ($self, $key) = @_;

    return delete $self->{_hash}{$key};
}

sub CLEAR {
    my $self = shift;

    %{$self->{_hash}} = ();
}

sub EXISTS {
    my ($self, $key) = @_;

    return exists $self->{_hash}{$key};
}

sub FIRSTKEY {
    my $self = shift;

    #build iterator     
    $self->{_list} = [ sort keys %{$self->{_hash}} ];    

    return $self->NEXTKEY;
}

sub NEXTKEY {
    my $self = shift;

    return shift @{$self->{_list}};
}

sub SCALAR {
    my $self = shift;
    return scalar %{$self->{_hash}};
}
like image 124
Chas. Owens Avatar answered Nov 22 '22 20:11

Chas. Owens