A sort of perl golf challenge
I've been reviewing some perl code code that is due to go back into Solaris shortly, and one of the routines takes a sorted array of integers and returns a string with contiguous ranges of numbers collapsed and other numbers comma-separated. For example, given an array containing 1, 3, 4, 5, 8, 9, 10, 12 the routine would return the string "1, 3-5, 8-10, 12". The routine iterates over the array looking for and collapsing sequences of numbers. It's 30 lines long, but always being one for taking up a pointless challenge I wondered if I could make it any shorter. Here's what I came up with:
sub collapse
{
my $str = join(', ', @_);
while ($str =~ s{\b(\d+), ((??{ $1 + 1 }))\b}{$1-$2}g) {}
$str =~ s{-(?:\d+-)+}{-}g;
return ($str);
}
Now I know that under the proper perl golf rules I could shorten that down by removing whitespace, using implicit assignment and matches against $_ and so forth but I'm more interested in seeing if anyone can come up with a conceptually shorter solution (i.e. one that I can still read ;-). It occured to me that you might be able to do something smart with a recursive regexp, but the requirement to use $1 + 1 to spot a sequence kept stymieing me. However I'm sure some other perl saddo out there will come up with something even shorter and far smarter. Anyone? ;-)
Re: A sort of perl golf challenge
I'm not a champion at Perl but here is my try.
I found that you can refer to whatever was matched by the most-recently closed group by using $^N inside the embedded Perl code.
The collapse subroutine might now look like this:
sub collapse
{
my $str= join(', ', @_);
$str=~ s{(\d+)(?:, ((??{ $^N + 1 })))+}{$1-$2}g;
return( $str);
}
I don't find it more obscure than the previous subroutine. What do you think?
Re: A sort of perl golf challenge
sub collapse {
my $str = join ', ', @_;
$str =~ s/(\d+)(?:, ((??{$^N + 1})))+/$1-$^N/g;
return $str;
}
But I just noticed it’s buggy without the \b assertions your initial attempt had:
sub collapse {
my $str = join ', ', @_;
$str =~ s/\b(\d+)(?:, ((??{$^N + 1})\b))+/$1-$^N/g;
return $str;
}
PS.: it would be nice if <code> tags were permitted in comments…