I was also thinking about iterators, I like the idea and I have written quite a number of them over the last years. Here, however, I would tend to prefer only one iterator that would keep a buffer of the unused A values and return a pair of A and B values when needed.
The following was written directly at the command line and is not an iterator (in the sense that it is not a subroutine returning the next relevant element), but it is iterating only once over the input data and it would be simple to put that code into an iterator closure that would keep track of the A buffer and return the A and the B values on demand:
$ perl -e '
> use strict;
> use warnings;
> my @in = split /\n/,
> "a 123
> a 125
> b 127
> a 129
> a 130
> b 131
> a 132
> b 133";
>
> my @a_buff;
> for (@in) {
> push @a_buff, $_ and next if /a/;
> my $aa = shift @a_buff; # avoid to use the $a special variable
> my $diff = $2 - $1 if "$aa - $_" =~ /(\d+)[^\d]*(\d+)/;
> print "$aa ; $_ => $diff\n";
> }
> '
a 123 ; b 127 => 4
a 125 ; b 131 => 6
a 129 ; b 133 => 4
Update: I have now done a full-fledged iterator as a closure:
use strict;
use warnings;
my $iter = create_iter();
while (my ($aa, $bb) = $iter->()) {
last unless defined $bb;
my $diff = $2 - $1 if "$aa $bb" =~ /(\d+)[^\d]*(\d+)/;
print "$aa ; $bb => $diff\n";
}
sub create_iter {
my @a_buff;
return sub {
while (<DATA>){
chomp;
push @a_buff, $_ and next if /a/;
return shift @a_buff, $_;
}
}
}
__DATA__
a 123
a 125
b 127
a 129
a 130
b 131
a 132
b 133
And this prints the same result:
$ perl iter_pairs.pl
a 123 ; b 127 => 4
a 125 ; b 131 => 6
a 129 ; b 133 => 4
Update 2: the same using a state variable (we are stuck with old versions of Perl at work, so I sometimes don't think about such relatively new features which, in this case, make the code a bit simpler than a closure):
use strict;
use warnings;
use feature "state";
while (my ($aa, $bb) = iter()) {
last unless defined $bb;
my $diff = $2 - $1 if "$aa $bb" =~ /(\d+)[^\d]*(\d+)/;
print "$aa ; $bb => $diff\n";
}
sub iter {
state @a_buff;
while (<DATA>){
chomp;
push @a_buff, $_ and next if /a/;
return shift @a_buff, $_;
}
}
__DATA__
a 123
...
|