我几乎想说“这是我了!”。
无论如何,我们走了。
我喜欢使用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 }
}
有更好的方法吗?我在疯狂吗?
我尝试了池上的建议。当然,Ikegami的例子完美无瑕。当我尝试抽象一点时,所有暴露给对象的东西都是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()循环的第一步。
我显然在这里遗漏了一些东西......
答案 0 :(得分:4)
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
中关于领带哈希的部分也有这样的例子。
答案 1 :(得分:4)
如果你不想依赖哈希的内置迭代器(由每个,键和值使用),那就没有什么可以阻止你制作自己的了。
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});
}
答案 2 :(得分:3)
以下是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;
答案 3 :(得分:1)
好吧,如果您以后不需要$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
循环。