I was poking around cpan the other day and I found this lovely function named "array_pad", whose stated purpose was to take a size, a scalar and a list, and to produce a padded list using the new size. If the size is possitive, the scalar is replicated on the right side of the list (that is, pushed) and if the size is negative, the scalar is added on the left hand side of the array (that is, pushed). So in other words, you take a size, a scalar and a list and produce a new list that is padded with the appropiate number of scalars. If size is smaller than the list, then nothing happens and you may return the original array.

The actual implementation of the function is thus:
#Returns a copy of the input padded to size specified by pad_size with + value pad_value. #If pad_size is positive then the array is padded on the right, if it' +s negative then on the left. #If the absolute value of pad_size is less than or equal to the length + of the input then no padding takes place. #int pad_size, mixed pad_value, array input sub array_pad{ my($pad_size, $pad_value, @array) = @_; #this is just to get the absolute value of the pad_size my $temp = $pad_size; if($pad_size < 0){ $temp = $temp * -1; }#if #first let's see if the pad_size is less than or equal to the arra +y size, return 0 no padding my $input_size = @array; if($temp <= $input_size){ return 0; }#if #since it didn't return 0, time to pad #if the pad_size is < 0, pad on the left, else the right if($pad_size < 0){ my @retval; $temp = $temp - $input_size; for(my $i=0;$i<$temp;$i++){ unshift(@array, $pad_value); }#for return @array; }#if else{ $temp = $pad_size - $input_size; for(my $i=0;$i<$temp;$i++){ push(@array, $pad_value); }#for return @array; }#else }#array_pad
And of course I immediately thought "How could I golf this?" and after a couple of rounds on IRC I produced this:
sub p{my($i,$z,@f)=@_;abs$i>@f&&$i<0?@f=(($z) x abs($i+@f),@f):(@f[@f. +.$i-1]=($z)x($i-@f));@f}
Which is really fairly long, and I know there are better solutions, because other people wrote some =].

This is the test suite used to test entries:
use Test::More tests => 4; my @x = 1 .. 5; is_deeply([p( 3, 'x', @x)], [ @x ]); is_deeply([p(-3, 'x', @x)], [ @x ]); is_deeply([p( 7, 'x', @x)], [ @x, 'x', 'x' ]); is_deeply([p(-7, 'x', @x)], [ 'x', 'x', @x ]);

Where p() is the function you've written. So can anyone come up with something shorter than mine (you certainly should), or shorter than 60 chars (which is the shortest one I've seen)?

Replies are listed 'Best First'.
Re: Golfing Array_Pad (54)
by Zaxo (Archbishop) on Jan 23, 2005 at 06:12 UTC

    Forget splice

    sub p { # my($c,$s,@x)=@_;my@a=($s)x(-@x+abs$c);$c>0?(@x,@a):(@a,@x) ($*,$^,@#)=@_;@*=($^)x(-@#+abs$*);$*>0?(@#,@*):(@*,@#) #234567890123456789012345678901234567890123456789012345678 }
    Now 58 54 and still strict.

    (Added) A word of explanation. If the multiplier is zero or negative, ($foo) x $bar returns an empty list. Punctuation variables are a vile trick.

    After Compline,
    Zaxo

      With slightly easier to read vars:

      sub p{($a,$b,@_)=@_;@*=($b)x(-@_+abs$a);$a>0?(@_,@*):(@*,@_)}

      Also the prototype of abs makes this annoying, i thought you could reorder the -@_+abs$a to lose one of the operators but the abs() then requires parens. Nice one by the way. :-)

      ---
      demerphq

Re: Golfing Array_Pad
by Zaxo (Archbishop) on Jan 23, 2005 at 05:29 UTC

    This is a natural for splice,

    sub p{ my($c,$s,@x)=@_;abs$c>@x&&splice@x,$c>0?@x:0,0,($s)x(-@x+abs$c);@x #234567890123456789012345678901234567890123456789012345678901234567 }
    I claim 66 and strict.

    After Compline,
    Zaxo

Re: Golfing Array_Pad
by PodMaster (Abbot) on Jan 23, 2005 at 05:48 UTC
    I haven't examined the code past the fact that your implementation and array_pad don't match up
    #Returns a copy of the input padded to size specified by pad_size with + value pad_value. #If pad_size is positive then the array is padded on the right, if it' +s negative then on the left. #If the absolute value of pad_size is less than or equal to the length + of the input then no padding takes place. #int pad_size, mixed pad_value, array input sub array_pad{ my($pad_size, $pad_value, @array) = @_; #this is just to get the absolute value of the pad_size my $temp = $pad_size; if($pad_size < 0){ $temp = $temp * -1; }#if #first let's see if the pad_size is less than or equal to the arra +y size, return 0 no padding my $input_size = @array; if($temp <= $input_size){ return 0; }#if #since it didn't return 0, time to pad #if the pad_size is < 0, pad on the left, else the right if($pad_size < 0){ my @retval; $temp = $temp - $input_size; for(my $i=0;$i<$temp;$i++){ unshift(@array, $pad_value); }#for return @array; }#if else{ $temp = $pad_size - $input_size; for(my $i=0;$i<$temp;$i++){ push(@array, $pad_value); }#for return @array; }#else }#array_pad sub p{my($i,$z,@f)=@_;abs$i>@f&&$i<0?@f=(($z) x abs($i+@f),@f):(@f[@f. +.$i-1]=($z)x($i-@f));@f} use Test::More tests => 4; my @x = 1 .. 5; is_deeply([p( 3, 'x', @x)], [array_pad( 3, 'x', @x)]); is_deeply([p(-3, 'x', @x)], [array_pad(-3, 'x', @x)]); is_deeply([p( 7, 'x', @x)], [array_pad( 7, 'x', @x)]); is_deeply([p(-7, 'x', @x)], [array_pad(-7, 'x', @x)]); __END__ 1..4 not ok 1 # Failed test (golfing.array_pad.pl at line 43) # Structures begin differing at: # $got->[0] = '1' # $expected->[0] = '0' not ok 2 # Failed test (golfing.array_pad.pl at line 44) # Structures begin differing at: # $got->[0] = '1' # $expected->[0] = '0' ok 3 ok 4 # Looks like you failed 2 tests of 4.

    MJD says "you can't just make shit up and expect the computer to know what you mean, retardo!"
    I run a Win32 PPM repository for perl 5.6.x and 5.8.x -- I take requests (README).
    ** The third rule of perl club is a statement of fact: pod is sexy.

      Congratulations, you've found one of the (I'm sure many) bugs in array_pad, but I don't feel that the bugs in array_pad are really relevant to the golfing contest, do you?
        And here I thought it might've been a bug in your implementation. If you knew array_pad was flawed, you should've mentioned it. I'm sure I wouldn't have been the first to think that the reference implementation would be correct and could be used to verify results.

        MJD says "you can't just make shit up and expect the computer to know what you mean, retardo!"
        I run a Win32 PPM repository for perl 5.6.x and 5.8.x -- I take requests (README).
        ** The third rule of perl club is a statement of fact: pod is sexy.

Re: Golfing Array_Pad
by holli (Abbot) on Jan 23, 2005 at 11:15 UTC
    this is my best attempt (and my first golf, so please be kind ,):
    sub p { my($a,$z,@x)=@_; my @n=($z)x(abs @x-abs $a); @n=abs $a>@x?$a<0?(@n,@x):(@x,@n):@x; }
    It passes strict; and warnings;

    Update:
    slightly optimized(71; less whitespace, stolen tricks ,)
    sub p {($a,$b,@x)=@_;@_=($b)x(abs@x-abs$a);@_=abs$a>@x?$a<0?(@_,@x):(@ +x,@_):@x}
    Why can i omit "my" here?

    holli, regexed monk

      Why can i omit "my" here?

      You can't.

      Global symbol "@x" requires explicit package name at c:\temp\a_sub.pl +line 8. Global symbol "@x" requires explicit package name at c:\temp\a_sub.pl +line 8. Global symbol "@x" requires explicit package name at c:\temp\a_sub.pl +line 8. Global symbol "@x" requires explicit package name at c:\temp\a_sub.pl +line 8. Global symbol "@x" requires explicit package name at c:\temp\a_sub.pl +line 8. Global symbol "@x" requires explicit package name at c:\temp\a_sub.pl +line 8. Execution of c:\temp\a_sub.pl aborted due to compilation errors.
      ---
      demerphq

        Yes I can.
        use strict; use warnings; use Test::More tests => 5; my @x = 1 .. 5; is_deeply([p( 3, 'x', @x)], [ @x ]); is_deeply([p(-3, 'x', @x)], [ @x ]); is_deeply([p( 7, 'x', @x)], [ @x, 'x', 'x' ]); is_deeply([p(-7, 'x', @x)], [ 'x', 'x', @x ]); @x = (); is_deeply([p(-4, 'x', @x)], [ 'x', 'x', 'x', 'x' ]); sub p {($a,$b,@x)=@_;@_=($b)x(abs@x-abs$a);@_=abs$a>@x?$a<0?(@_,@x):(@ +x,@_):@x}
        Update:
        oh dear, @x is a global. silly, me.

        holli, regexed monk
Re: Golfing Array_Pad [55]
by demerphq (Chancellor) on Jan 24, 2005 at 12:01 UTC

    55 chars and strict compliant

    sub p{($a,$b,@_)=@_;@_<abs$a?p($a,$b,$a<0?($b,@_):(@_,$b)):@_} # 1 2 3 4 5 # 1234567890123456789012345678901234567890123456789012345
    ---
    demerphq