#! /usr/bin/perl

use strict;

# simple & ugly code to test the subroutines
# (has also been tested with other lists, including negative numbers)

my @list = (1, 2, 4, 5, 6, 7, 9, 13, 24, 25, 26, 27);
my $string = "1-2, 4-7, 9, 13, 24-27";

my $result = format_number_list(@list);
print "format_number_list()\n";
print "input list  : (", join(" ",@list),")\n";
print "result      : '$result'\n" ;
print "should be   : '$string'\n" ;
print "\n";

print "expand_number_list()\n";
my @result = expand_number_list($string);
print "input string: '$string'\n" ;
print "result      : (", join(" ",@result),")\n";
print "should be   : (", join(" ",@list),")\n";
print "\n";

sub format_number_list {
  # sort the input list numerically, just in case it isn't already sorted
  my(@integers) = sort {$a <=> $b} @_;

  my @out = ();

  # keep track of the start and end of each sequence of consecutive numbers
  my $start = 0;
  my $end = 0;

  for my $i (1..@integers) {
    # skip duplicates
    next if ($integers[$i] == $integers[$end]);

    # are we still in the same 'sequence'?
    if ($integers[$i] == $integers[$end] + 1) { $end++; next};

    # nope, this 'sequence' has ended. add it to @out, whatever it is.
    if ($start == $end) {   
      # a 'sequence' of only one number
      push @out, $integers[$start];
    } else {
      # a sequence of two or more numbers
    
      # make the output 'nicer' to read out-loud by adding a plus sign
      # when a sequence goes from -ve to +ve.
      my $sign = (($integers[$start] <0) && ($integers[$end]>0)) ? '+' : '';
      push @out, "$integers[$start]-$sign$integers[$end]";

      # alternatively, don't do that.
      #push @out, "$integers[$start]-$integers[$end]";
    };
    # reset start and end counters to current array element
    $start = $i; $end = $i;
  };

  return join(", ",@out);
};


sub expand_number_list {
  my $string = shift;
  # split the input string, ignoring any white space that might be there
  my @array = split(/\s*,\s*/,$string) ;

  my @out = ();

  foreach (@array) {
    # add spaces around the "-" in a sequence, to distinguish it
    # from the minus sign of negative integers.
    s/([-\d])-([-\d])/$1 - $2/;

    if (/ - /) {   
      # a sequence, expand it!
      my ($start,$end) = split / - /;
      for ($start .. $end) { push @out, $_ } ;
    } else {     
      # not a sequence
      push @out, $_;
    };
  };
  return @out;
  # it just occurred to me that this should return a sorted array,
  # just in case the input is in some weird order.  that would 
  # be:
  # return sort {$a <=> $b} @out;
};

