The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
use strict;
use Benchmark qw{:all};

#my @arr = map { [map { rand(100) } (1 .. 23)] } (1 .. 23);
#my @arr = map { [map { rand(100) } (1 .. 347)] } (1 .. 23);
my @arr = map { [map { rand(100) } (1 .. 1009)] } (1 .. 23);

my $id = sub { $_[0] };

my $counter = 0;
sub get_next{ $arr[ $counter++ % @arr ] }
sub get_rand{ $arr[ int(@arr * rand) ] }

cmpthese(10000, {
	'counter' => sub {
		my @arr = (get_next(), get_rand());

		my %set;
		do { ++$set{$_} for @$_ } for @arr;
		return map { [grep { $set{$_} == 1 } @$_] } @arr;
	},
	'undef' => sub {
		my $index = 0;
	  my @results = ([]) x 2;
		my %set;

		for (get_next(), get_rand()) {
			$set{$_} = exists $set{$_} ? undef : $index for @$_;
			++$index;
		}

		while (my ($key, $index) = each %set) {
			next unless defined $index;
			push @{$results[$index]}, $key;
		}

		return @results;
	},
});

cmpthese(10000, {
	'counter_m' => sub {
		my @arr = (get_next(), get_rand(), get_rand(), get_rand(), get_rand());

		my %set;
		do { ++$set{$_} for @$_ } for @arr;
		return map { [grep { $set{$_} == 1 } @$_] } @arr;
	},
	'undef_m' => sub {
		my $index = 0;
	  my @results = ([]) x 5;
		my %set;

		for (get_next(), get_rand(), get_rand(), get_rand(), get_rand()) {
			$set{$_} = exists $set{$_} ? undef : $index for @$_;
			++$index;
		}

		while (my ($key, $index) = each %set) {
			next unless defined $index;
			push @{$results[$index]}, $key;
		}

		return @results;
	},
});

=head
cmpthese(10000, {

	'exists_fn' => sub {
		my $lhs = get_next();

		my %set;
		@set{ map { $id->($_) } @$lhs } = @$lhs;

		for (get_rand(), get_rand(), get_rand(), get_rand()) {
			my @int = grep { exists $set{$id->($_)} } @$_;
			return unless @int;
			undef %set;
			@set{ map { $id->($_) } @int } = @int;
		}
		return keys %set;
	},

	'slice_defined_fn' => sub {
		my $lhs = get_next();

		my %set;
		@set{ map { $id->($_) } @$lhs } = @$lhs;

		for (get_rand(), get_rand(), get_rand(), get_rand()) {
			my @int = grep { defined } @set{ map { $id->($_) } @$_ };
			return unless @int;
			undef %set;
			@set{ map { $id->($_) } @int } = @int;
		}
		return keys %set;
	},

});
=cut