Brad Baxter said:
[This stems somewhat from discussions in the thread:
Idiom for array index that I'm foreach'ing over?]
I'm considering making a new module with the tentative name Array::Each.
A draft is available here:
http://www.vitabrevis.ws/perl/modules/Array/Each.pm
http://www.vitabrevis.ws/perl/modules/Array/Each.pod.html
It's incomplete, but I want to discuss the idea before proceeding further.
1. Is Array::Each acceptable? Perhaps Array:
arallel, or
Array::Iteration?
2. Are the subroutine names acceptable? In particular, I expect negative
reactions to each(), since it would clobber each( %hash ), so alternative
suggestions are welcome.
3. Is this a good approach? Are all those options needed? Does it matter
that it doesn't return lvalues like foreach ( @array )?
4. Should someone else do this/Has someone else done this? I did study
the CPAN module list and didn't find a close match. That I missed one
would not surprise me.
5. I imagine sometime adding an OO interface along these lines:
my $set = Array::Each->new( @x, @y );
my( $i, $x, $y ) = $set->each();
By all means, go for an OO approach. This stuff has been shouting
"object" from the moment we introduced the %i hash with its keys to
distinguish different iterators.
Isn't there some type of Iterator package for perl? Why stop at arrays?
If there would be an OO approach, why not have iterators for many things.
Here is a simplified example of what Im thinking about.
It is using closures instead of full objects (for brevity);
package Iterator;
use strict;
use warnings;
# iterator over multiple arrays
sub arrays(;\@\@\@\@\@) {
my $arrays = [@_];
my $i = -1;
my $mi = -1;
foreach(@_) { $mi = $#{$_} if ($#{$_} > $mi) }
return sub {
return () if ($i >= $mi);
return (++$i, map{$_->[$i]} @{$arrays});
};
}
# iterate over multiple hashes
sub hashes(;\%\%\%\%\%) {
my $hashes = [@_];
my %keys;
map{$keys{$_}=1} keys %{$_} foreach(@_);
my @keys = keys %keys;
my $i = -1;
return sub {
return () if ($i >= $#keys);
return ($keys[++$i], map{$_->{$keys[$i]}} @{$hashes});
};
}
# iterate over 2d array
sub array2d {
my ($x,$y) = (-1,0);
my $array = ($#_ == 0 and UNIVERSAL::isa($_[0], 'ARRAY')) ? $_[0] : [@_];
my $my = $#{$array};
my $mx = ($my >= 0) ? $#{$array->[0]} : -1;
return sub {
if (++$x > $mx) { $y++; $x=0 }
return () if ($y > $my);
return ($y,$x,$array->[$y][$x]);
};
}
# Find and load dynamic iterator
sub find_iterator {
my $imod = shift;
print "imod = $imod\n";
my $imod_file = "Iterator/$imod";
$imod_file =~ s/::/\//g;
$imod_file .= ".pm";
require $imod_file;
no strict 'refs';
my $get_iter = \&{*{"Iterator::${imod}::iterator"}};
warn "not iterator found for $imod\n" and return unless($get_iter);
return $get_iter->(@_);
}
package main;
use strict;
use warnings;
no warnings 'uninitialized';
my @a = qw/ 1 2 3 4/;
my @b;
my @c = qw/6 7 8 9/;
my $iter_a = Iterator::arrays(@a,@b,@c);
while (my ($i,$v1,$v2,$v3) = $iter_a->()) {
print "[$i] ($v1,$v2,$v3)\n";
}
print "-" x 40, "\n";
my %a = (a=>1,b=>2,c=>3);
my %b = (z=>99);
my %c = (xx=>'xx',hash=>\%a);
my $iter_b = Iterator::hashes(%a, %b, %c);
while (my ($k,$v1,$v2,$v3) = $iter_b->()) {
print "[$k] ($v1,$v2,$v3)\n";
}
print "-" x 40, "\n";
my $array = [
[1,2,3],
[4,5,6],
[7,8,9]
];
my $iter_c = Iterator::array2d($array);
while (my ($y,$x,$value) = $iter_c->()) {
print "($y,$x) = ($value)\n";
}
print "-" x 40, "\n";
my $iter_d = Iterator::find_iterator('files', "*.pl");
while (my ($i, $file) = $iter_d->()) {
print "[$i] = $file\n";
}
# Iterator/files.pm
package Iterator::files;
use strict;
use warnings;
sub iterator {
my @files = sort glob(shift);
my $i = -1;
return sub {
return () if (++$i > $#files);
return ($i, $files[$i]);
};
}
return 1;