NAME

Iterator::Array::Jagged - Quickly permute and iterate through multiple jagged arrays.

SYNOPSIS

use Iterator::Array::Jagged;

# Build up a set of data:
my @data = (
	[qw/ a b /],
	[qw/ c d /],
	[qw/ e f g /]
);

# Iterator in object-oriented mode:
my $iterator = Iterator::Array::Jagged->new( data => \@data );
while( my @set = $iterator->next )
{
	print "Next set: '" . join("&", @set) . "'\n";
}# end while()

# Iterator is a subref:
my $itersub = Iterator::Array::Jagged->get_iterator( @data );
while( my @set = $itersub->() )
{
	print "Next set: '" . join("&", @set) . "'\n";
}# end while()

# Functional callback style:
Iterator::Array::Jagged->permute(sub {
	my (@set) = @_;
	print "Next set: '" . join("&", @set) . "'\n";
}, @data );

Each example in the code above code prints the following:

Next set: b&c&e'
Next set: a&d&e'
Next set: b&d&e'
Next set: a&c&f'
Next set: b&c&f'
Next set: a&d&f'
Next set: b&d&f'
Next set: a&c&g'
Next set: b&c&g'
Next set: a&d&g'
Next set: b&d&g'

DESCRIPTION

Iterator::Array::Jagged can permute through sets of "jagged" arrays - arrays of varying lengths.

Iterator::Array::Jagged works much like the odometer in an automobile. Except that each set of "numbers" can have any kind of data you want, and each set can contain 1 or more elements.

Iterator::Array::Jagged is stable and ready for production use as of version 0.05.

METHODS

new( %args )

Constructor. %args should included the element data which contains the arrayref of arrayrefs that you wish to iterate through.

next( )

Returns an array representing the next iteration of the permutation of your data set. See the synopsis for an example.

get_iterator( @data )

Returns a coderef that, when called, returns the next set of data until there are no more permutations. See the synopsis for an example.

permute( $subref, @data )

Calls $subref for each permutation in @data. This is currently BY FAR THE FASTEST METHOD AVAILABLE.

BENCHMARKS

After the initial release of Iterator::Array::Jagged, some people were wondering if there was any benefit to using I::A::J over another older module Algorithm::Loops and its NestedLoops method. So I did some benchmarking and found some mixed results.

                  Rate I::A::J OO A::L::NL func I::A::J iterator A::L::NL iterator I::A::J permute
I::A::J OO        4.19/s         --           -3%             -19%              -29%            -45%
A::L::NL func     4.32/s         3%            --             -16%              -27%            -43%
I::A::J iterator  5.15/s        23%           19%               --              -12%            -32%
A::L::NL iterator 5.88/s        40%           36%              14%                --            -22%
I::A::J permute   7.58/s        81%           75%              47%               29%              --

Depending on the size and depth of the jagged array data passed in, the results vary slightly. However, the order in which each method finishes is the same. Iterator::Array::Jagged->permute is fastest by a signifigant margin over Algorithm::Loops::NestedLoops. On the opposite end of the spectrum we have the OO method of Iterator::Array::Jagged which comes in at nearly half the speed of the permute option.

The benchmark script that was used is shown in the next section.

Benchmarks were done on a server with the following specs:

CPU:

Intel(R) Core(TM)2 CPU 6400 @ 2.13GHz stepping 02

RAM:

2Gb

The Benchmark Script

#!/usr/bin/perl -w

use strict;
use Time::HiRes qw(gettimeofday);
use Benchmark qw' :all ';

use Algorithm::Loops 'NestedLoops';
use Iterator::Array::Jagged;


my @data = ();
for my $var ( 1...4 )
{
  my @set = ();
  my $max = $var % 2 ? 10 : 11;
  for my $val ( 1...$max )
  {
    push @set, "var$var=val$val";
  }# end for()
  push @data, \@set;
}# end for()

cmpthese( 20, {
  'I::A::J OO'        => sub { do_iterator_array_jagged( @data ) },
  'A::L::NL iterator' => sub { do_nestedloops_iterator( @data ) },
  'A::L::NL func'     => sub { do_nestedloops_func( @data ) },
  'I::A::J permute'   => sub { do_iaj_permute( @data ) },
  'I::A::J iterator'  => sub { do_iaj_iterator( @data ) },
});


sub do_iaj_iterator
{
  my $iter = Iterator::Array::Jagged->get_iterator( @_ );
  while( my @set = $iter->() )
  {
  }# end while()
}# end do_iaj_iterator()


sub do_iaj_permute
{
  Iterator::Array::Jagged->permute( sub { }, @_ );
}# end do_iaj_permute()


sub do_iterator_array_jagged
{
  my @data = @_;
  my $iter = Iterator::Array::Jagged->new( data => \@data );
  while( my $set = $iter->next )
  {
  }# end while()
}# end do_iterator_array_jagged()


sub do_nestedloops_func
{
  NestedLoops( \@_, sub { } );
}# end do_nestedloops_func()


sub do_nestedloops_iterator
{
  my @data = @_;
  my $iter = NestedLoops( \@data );
  while( my @set = $iter->() )
  {
  }# end while()
}# end do_nestedloops()

BUGS

It's possible that some bugs have found their way into this release.

Use RT http://rt.cpan.org/NoAuth/Bugs.html?Dist=Iterator-Array-Jagged to submit bug reports.

AUTHOR

John Drago mailto:jdrago_999@yahoo.com

COPYRIGHT AND LICENSE

Copyright 2007 John Drago, All rights reserved.

This software is free software. It may be used and distributed under the same terms as Perl itself.