use Benchmark qw/cmpthese/; use List::Util qw/reduce/; sub kvmap (&@) { my ( $f, @kv ) = @_; my $key = 0; local ( $a, $b ); return map { ( $key ^= 1 ) ? do { $a = $_; () } : do { $b = $_; $f->($a, $b) } } @kv; } my @data = my %data = ( action => 'submit', type => 'comment', message => 'Hello' ); cmpthese -5, { ex1 => sub { my @output; while ( my ($k,$v) = splice(@data,0,2) ) { push @output, "$k=$v" } join( "&", @output ); }, ex2 => sub { my @output; my @copy = @data; while ( my ($k,$v) = splice(@copy,0,2) ) { push @output, "$k=$v" } join( "&", @output ); }, ex3 => sub { my @output; while ( my ($k,$v) = each %data ) { push @output, "$k=$v" } join( "&", @output ); }, ex4 => sub { join "&", map { "$_->[0]=$_->[1]" } map { @$_ } reduce { ! @$a || ref $a->[-1] ? push @$a, $b : push @$a, [pop @$a, $b]; $a } [], @data; }, ex5 => sub { join "&", map { @{$_->[0]} } reduce { ref $a->[-1] ? push @$a, $b : push @{$a->[0]}, pop(@$a) . "=$b"; $a } [[]], @data; }, inline_kvmap => sub { my $key = 0; local ( $a, $b ); join '&', map { ( $key ^= 1 ) ? do { $a = $_; () } : do { "$a=$_" } } @data; }, call_kvmap => sub { join '&', kvmap { "$a=$b" } @data; } };