My take (with tests):
#!/usr/local/bin/perl
use strict;
use warnings FATAL => 'all';
sub fill_in_the_blanks {
my @arr = @_;
die "No values found" if @arr && 0 == grep $_ ne '_', @arr;
for (my $left = 0; $left < @arr; $left++) {
next unless $arr[$left] eq '_';
my $right = $left;
$right++ while $right < $#arr && $arr[$right+1] eq '_';
if ($left == 0) { # NULLs at the left
$arr[$_] = $arr[$right+1] for $left..$right;
}
elsif ($right == $#arr) { # NULLs at the right
$arr[$_] = $arr[$left-1] for $left..$right;
}
elsif ($left == $right) { # single
$arr[$left] = ($arr[$left-1] + $arr[$left+1]) / 2;
}
else {
$arr[$left ] = $arr[$left -1];
$arr[$right] = $arr[$right+1];
}
}
return @arr;
}
use Test::Most;
is_deeply [fill_in_the_blanks(qw< >)], [qw< >], "( )";
is_deeply [fill_in_the_blanks(qw<1>)], [qw<1>], "(1)";
throws_ok { fill_in_the_blanks(qw< _ >) } qr{No values found}, "( _
+ )";
throws_ok { fill_in_the_blanks(qw< _ _ >) } qr{No values found}, "( _
+_ )";
throws_ok { fill_in_the_blanks(qw<_ _ _>) } qr{No values found}, "(_ _
+ _)";
is_deeply [fill_in_the_blanks(qw<1 _ 1>)], [qw<1 1 1>], "(1 _ 1)";
is_deeply [fill_in_the_blanks(qw<1 _ 3>)], [qw<1 2 3>], "(1 _ 3)";
is_deeply [fill_in_the_blanks(qw<1 _ _ 3>)], [qw<1 1 3 3>], "(1 _
+ _ 3)";
is_deeply [fill_in_the_blanks(qw<1 _ _ _ 3>)], [qw<1 1 2 3 3>], "(1 _
+_ _ 3)";
is_deeply [fill_in_the_blanks(qw<1 _>)], [qw<1 1>], "(1 _)";
is_deeply [fill_in_the_blanks(qw<1 _ _>)], [qw<1 1 1>], "(1 _ _)";
is_deeply [fill_in_the_blanks(qw<_ 1>)], [qw<1 1>], "(_ 1)";
is_deeply [fill_in_the_blanks(qw<_ _ 1>)], [qw<1 1 1>], "(_ _ 1)";
is_deeply [fill_in_the_blanks(qw<4 _ _ _ 5>)], [qw<4 4 4.5 5 5>], "dhu
+ang90";
done_testing;
The results...
ok 1 - ( )
ok 2 - (1)
ok 3 - ( _ )
ok 4 - ( _ _ )
ok 5 - (_ _ _)
ok 6 - (1 _ 1)
ok 7 - (1 _ 3)
ok 8 - (1 _ _ 3)
ok 9 - (1 _ _ _ 3)
ok 10 - (1 _)
ok 11 - (1 _ _)
ok 12 - (_ 1)
ok 13 - (_ _ 1)
ok 14 - dhuang90
1..14
An interesting little problem. It has lots of edge cases and so makes a nice code kata. Thank for posting it.