in reply to Expand Ranges in Lists of Numbers

Very interesting, and potentially very, very useful. It might also be useful to have the reverse function, compacting a list of numbers into a list containing ranges.

The code below seems to do this, with the caveats that:

  1. if numbers appear twice in the list, only one instance is returned,
  2. the original ordering is lost, as the values in this code are sorted to ease processing, and
  3. the code is a sample, and someone more skilled would probably be able to do the same better or more efficiently

With that in mind, here is my contribution:

sub compactRanges { # # @pieces contains the list of numbers # %parts will contain a compact form, such that $start..$end # is represented as $parts{$start} = $end # $seperator contains the character(s) placed between the # values # %wrap_negatives contains a flag indicated if negative # values should be wrapped in some way, and the leading # and trailing values if so # my (@pieces) = @_; my $seperator = '..'; my %wrap_negatives = ( 'flag' => 1, 'leading' => '[', 'trailing' => ']' ); my (%parts); @pieces = sort { $a <=> $b } @pieces; { my ($i); my ($recent); $recent = $parts{$i} = $i = shift (@pieces); while (@pieces) { $i = shift (@pieces); $recent = $i if ( $i - 1 > $parts{$recent} ); $parts{$recent} = $i; } } foreach my $k ( sort { $a <=> $b } keys(%parts) ) { my $str = ( ( $wrap_negatives{'flag'} ) and ( $k < 0 ) ? $wrap_negatives{'leading'} : '' ) . $k . ( ( $wrap_negatives{'flag'} ) and ( $k < 0 ) ? $wrap_negatives{'trailing'} : '' ); $str .= $seperator . ( ( $wrap_negatives{'flag'} ) and ( $parts{$k} < 0 ) ? $wrap_negatives{'leading'} : '' ) . $parts{$k} . ( ( $wrap_negatives{'flag'} ) and ( $parts{$k} < 0 ) ? $wrap_negatives{'trailing'} : '' ) if ( $parts{$k} != $k ); push ( @pieces, $str ); } return (@pieces); }

Replies are listed 'Best First'.
Re: Re: Expand Ranges in Lists of Numbers
by The Mad Hatter (Priest) on Jun 08, 2003 at 22:01 UTC