#!/usr/bin/perl
use strict;
use warnings;
use List::Util 'sum';
use constant TESTS => 20;
use Test::More tests => TESTS;
sub naive {
my @arr = map +($_) x $_[$_], 0..$#_;
@arr % 2 ?
@arr[(@arr-1)/2] :
(@arr[@arr/2 - 1] + @arr[@arr/2])/2;
}
sub findidx {
my $i=shift;
($i -= $_[$_])<0 and return $_ for 0..$#_;
}
sub smart {
my $t=sum @_;
$t%2 ?
findidx +($t-1)/2, @_ :
(findidx($t/2-1, @_) + findidx($t/2, @_))/2;
}
for (1..TESTS) {
my @a=map int rand 10, 0..5;
is smart(@a), naive(@a), "Test @a";
}
__END__
Here, if I were not to have findidx() as a separate sub but inline its code/logic into smart(), I would probably do it like thus:
sub smart {
my $t=sum @_;
if ($t%2) {
my $i=($t-1)/2;
($i -= $_[$_])<0 and return $_ for 0..$#_;
} else {
my $i=$t/2-1;
my ($found1, $found2);
for (0..$#_) {
($found1=$_), last if ($i -= $_[$_])<0;
}
my $j=$t/2;
for (0..$#_) {
($found2=$_), last if ($j -= $_[$_])<0;
}
return ($found1+$found2)/2;
}
}
Of course there are other WTDI as usual, however one cannot but notice that in this particular case not only did factoring code away in a sub reduce duplication, but it even gave one the possibility of applying some syntactic sugar that makes code overall more terse and clear.
Update: switched from spoiler tags around the minimal description to readmore at Argel's request.
|