[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