相当于"shift"哈希创建 $class->next() 方法



我几乎想说"又是我!"

不管怎样,我们开始吧。

我喜欢使用while $object->next()风格的结构。它们对我很有吸引力,看起来很"整洁"。

现在,当我要迭代的对象是一个数组时,它很简单(" shift @ary or return undef ")

sub next {
   my ( $self, $args ) = @_;
   my $next = shift @{ $self->{list_of_things} } or return undef;
   my ( $car, $engine_size, $color )
       = split( /Q$opts->{fieldsep}/, $next );
   $self->car         = $host;
   $self->engine_size = $engine_size;
   $self->color       = $color;

}

在这个例子中,我使用AUTOLOAD来创建getter和setter,然后在while循环期间在我的对象中使用这些实例变量。

我想做一些类似的事情,但"list_of_things"是一个%hash

这是一个没有进入第一次迭代的非oo示例。知道为什么吗?

(总的"list_of_things"不是那么大——可能有100个条目——所以每次做一个keys(%{$hash})对我来说似乎并不太浪费)。

use strict;
use warnings;
use Data::Dumper;
my $list_of_things = {
    volvo => {
        color => "red",
        engine_size => 2000,
    },
    bmw => {
        color => "black",
        engine_size => 2500,
    },
    mini => {
        color => "british racing green",
        engine_size => 1200,
    }
};
sub next {
    my $args = $_;
    my @list = keys( %{$list_of_things} );
    return undef if scalar @list == "0";
    my $next = $list_of_things->{ $list[0] };
    delete $list_of_things->{ $list[0] };
    return $next;
}
while ( next()) {
    print Dumper $_;
    print scalar keys %{ $list_of_things }
}

有更好的方法吗?我是不是做了什么疯狂的事?

<标题>编辑:

我尝试了池上的建议。当然,池上的例子是完美的。当我尝试抽象一点,以便所有暴露给对象的都是next->()方法时,我得到了与原始示例相同的"perl-going-to-100%-cpu"问题。

下面是一个非oo的例子:

use Data::Dumper qw( Dumper );
sub make_list_iter {
   my @list = @_;
   return sub { @list ? shift(@list) : () };
}
sub next {
   make_list_iter( keys %$hash );
}
my $hash = { ... };
while ( my ($k) = next->() ) {
   print Dumper $hash->{$k};
}

它似乎没有通过while()循环的第一步。

如果你不想依赖哈希的内置迭代器(每个键和值都使用),没有什么可以阻止你自己创建。

use Data::Dumper qw( Dumper );
sub make_list_iter {
   my @list = @_;
   return sub { @list ? shift(@list) : () };
}
my $list_of_things = { ... };
my $i = make_list_iter(keys %$list_of_things);
while (my ($k) = $i->()) {
   local $Data::Dumper::Terse  = 1;
   local $Data::Dumper::Indent = 0;
   say "$k: " . Dumper($list_of_things->{$k});
}

each操作符是一个内置的遍历哈希值的操作符。当返回的元素用完时返回undef。所以你可以输入

package SomeObject;
# creates new object instance
sub new {
    my $class = shift;
    return bless { hash_of_things => { @_ } }, $class
}
sub next {
    my $self = shift;
    my ($key,$value) = each %{ $self->{hash_of_things} };
    return $key;  # or return $value
}

对哈希值调用keys将重置each迭代器。知道这一点很好,这样你就可以故意重置它:

sub reset {
    my $self = shift;
    keys %{ $self->{hash_of_things} }
}

,这样你就可以避免在意外情况下重置它。

perltie中绑定哈希的部分也有一个这样的例子

下面是如何使用List::Gen从列表创建迭代器:

use strict;
use warnings;
use List::Gen 'makegen';
my @list_of_things = (   # This structure is more suitable IMO
    {
        make        => 'volvo',
        color       => 'red',
        engine_size => 2000,
    },
    {
        make        => 'bmw',
        color       => 'black',
        engine_size => 2500,
    },
    {
        make        => 'mini',
        color       => 'british racing green',
        engine_size => 1200,
    }
);
my $cars = makegen @list_of_things;
print $_->{make}, "n" while $cars->next;

如果你以后不需要$list_of_things,你总是可以这样做

while(keys %$list_of_things)
{
  my $temp=(sort keys %$list_of_things)[0];
  print "key: $temp, value array: " . join(",",@{$list_of_things->{$temp}}) . "n";
  delete $list_of_things->{$temp};
}

如果你确实需要它,你总是可以将它分配给一个临时哈希引用,并对它执行相同的while循环。

最新更新