Wednesday April 05, 2006
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? ;-)
Posted by alanbur
( Apr 05 2006, 10:20:31 PM BST )
Permalink
Comments [9]
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?
Posted by Hugues Ferland on October 16, 2006 at 07:27 PM BST #
Posted by Tony on February 01, 2007 at 11:08 PM GMT #
Posted by Alan Burlison on February 01, 2007 at 11:08 PM GMT #
sub collapse { my $str = join ', ', @_; $str =~ s/(\d+), ((??{$^N + 1})(?:, )?)+/$1-$^N/g; return $str; }Posted by Aristotle Pagaltzis on February 01, 2007 at 11:08 PM GMT #
Posted by Alan Burlison on February 01, 2007 at 11:08 PM GMT #
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…Posted by Aristotle Pagaltzis on February 01, 2007 at 11:08 PM GMT #
Posted by Aristotle Pagaltzis on February 01, 2007 at 11:08 PM GMT #
I don't know why code tags aren't allowed, but pre tags seem to work OK.
Posted by Alan Burlison on February 01, 2007 at 11:08 PM GMT #
Alan,
thats awesome I don't quite understand how this thing works could it return the data as arrays ?
somthing like this ?
"[1],[3,4,5],[8,9,10],[12]"
though for my purpose it would be better if "[]" these where "{}" these instead
Posted by Mike on March 21, 2008 at 01:15 PM GMT #