[Purdue-pm] my solution to challenge
Michael Gribskov
gribskov at purdue.edu
Wed Mar 24 10:08:06 PDT 2010
#!/usr/bin/perl -w
#------------------------------------------------------------------------------
# $Id:$
#
# Write a function, format_number_list, whose argument is a list of
# integers. It then returns a string which represents the input list in
# compact, human-readable form.
#
# For example,
# format_number_list(1, 2, 4, 5, 6, 7, 9, 13, 24, 25, 26, 27)
# will return
# "1-2, 4-7, 9, 13, 24-27"
#
# Also write a function, 'expand_number_list', which does the conversion
# in the opposite direction, so that
# expand_number_list("1-2, 4-7, 9, 13, 24-27")
# will return
# (1, 2, 4, 5, 6, 7, 9, 13, 24, 25, 26, 27)
#
# Michael Gribskov Mar 24, 2010
#
# Revision log at end of file
#------------------------------------------------------------------------------
use strict;
my @datalist = ( [],
[1, 4, 5, 6, 9, 13, 21, 22, 23, 25, 26, 27],
[1, 2, 3, 5, 6, 7, 9, 13, 15, 16, 17, 27],
[-27, -17, -16, -15, -13, -9, -7, -6, -5, -3, -2, -1],
[-27, -26, -25, -23, -22, -21, -13, -9, -6, -5, -4, -1],
[-8, -6, -5, -4, 9, 13, 21, 22, 23, 25, 26, 27],
[-6, -5, -4, 5, 6, 7, 9, 13, 15, 16, 17, 27],
[-8, -6, -5, -4, 0, 9, 13, 21, 22, 23, 25, 26, 27],
[-6, -5, -4, 0, 5, 9, 6, 7, 9, 13, 15, 16, 17, 27]
);
my @datacomment = ( 'null list',
'begins with singleton, ends with range',
'begins with range, ends with singleton',
'negative numbers, begin with singleton, end with
range',
'negative numbers, begin with range, end with
singleton',
'negative & positive numbers, begin with singleton,
end with range',
'negative & positive numbers, begin with range, end
with singleton',
'negative & positive numbers & zero, begin with
singleton, end with range',
'negative & positive numbers & zero, begin with
range, end with singleton',
);
foreach my $d ( 0 .. $#datalist ) {
my @data = @{$datalist[$d]};
print "\ntest $d: $datacomment[$d]\n";
print " data = [ @data ]\n";
print " original number list: @data\n";
my $numstring = formatNumberList( @data );
print " formatted number list: $numstring\n";
my @newlist = expandNumberList2( $numstring );
print " converted back to list: @newlist\n";
}
#------------------------------------------------------------------------------
# formatNumberList
#
# converts a list of numbers to a string where successive numbers are
given as
# as a range with a hyphen, e.g., 2,3,4 becomes 2-4. Works with negative
# numbers and zero, but produces an ugly double hyphen. The input
should be
# presorted
#
# USAGE
# $formatted_string = formatNumberList( @list );
#------------------------------------------------------------------------------
sub formatNumberList{
return "" unless @_; # return empty string for null input
my $n = shift;
my $str = $n;
my $end;
my $next = $n + 1;
# $end is a marker that tells a range has ben opened, and gives the
current
# end of the range. if $end is undef, the current number either
begins a
# range or is a singleton.
while ( @_ ) {
$n = shift;
if ( $n==$next ) {
# begin a new range
$str .= "-" unless $end;
$end = $n;
} else {
# end of a range, or a singleton
$str .= sprintf "%s, %d", $end||"", $n;
undef $end;
}
$next = $n+1;
}
$str .= $end if $end; # close last range if it is a range
return $str;
}
# End of formatNumberList
#------------------------------------------------------------------------------
# expandNumberList
#
# convert the string produced by formatNumberList back to a list. This
version
# only works for positive numbers.
#
# USAGE
# @list_of_numbers = expandNumberList( $number_list_string );
#------------------------------------------------------------------------------
sub expandNumberList{
my ( $numstring ) = @_;
my @numlist;
my @range = split /\s*,\s*/, $numstring; # split on comma with
spaces
foreach my $r ( @range ) {
my ( $begin, $end ) = split "-", $r;
unless ( defined $end ) { # $end is undef if not
a range
$end = $begin;
}
foreach my $i ( $begin .. $end ) {
push @numlist, $i;
}
}
return @numlist;
}
# End of expandNumberList
#------------------------------------------------------------------------------
# expandNumberList2
#
# convert the string produced by formatNumberList back to a list. This
version
# workks for zero, positive, and negative numbers
#
# USAGE
# @list_of_numbers = expandNumberList( $number_list_string );
#------------------------------------------------------------------------------
sub expandNumberList2{
my ( $numstring ) = @_;
my @numlist;
# break string up into ranges and singletons by splitting on
commas. just
# in case, allow space around the commas
my @range = split /\s*,\s*/, $numstring;
foreach my $r ( @range ) {
# get begin and end of range, if its a singleton, begin and end
are the same
my $begin = $r;
my $end = $r;
if ( $r =~ /\d-/ ) { # test if this is a range
# convert negative signs to x, to protect from split
$r =~ s/^-/x/;
$r =~ s/--/-x/;
# split and convert x back to negative
( $begin, $end ) = split "-", $r;
$begin =~ s/x/-/;
$end =~ s/x/-/;
}
# push range onto list.
foreach my $i ( $begin .. $end ) {
push @numlist, $i;
}
}
return @numlist;
}
# End of expandNumberList2
#------------------------------------------------------------------------------
# $Log:$
#------------------------------------------------------------------------------
--
Michael Gribskov
Hockmeyer Hall of Structural Biology
Purdue University
240 S. Martin Jischke Drive
West Lafayette, IN 47907
gribskov at purdue.edu vox: 765.494.6933 fax: 765.496-1189
calendar: http://www.google.com/calendar/embed?src=mgribskov%40gmail.com
More information about the Purdue-pm
mailing list