Drigan has asked for the wisdom of the Perl Monks concerning the following question:

Ok, so I've been playing with perl for a few weeks, and I've got an array of years that could look like this:

my @yearArray = (1992, 1994, 1995, 1997, 1998, 1999, 2000, 2002, 2004, 2005, 2006, 2007, 2008);

I want to make it look like this:
1992, 1994-1995, 1997-2000, 2002, 2004-2008

I've got something that seems to work . . . but it's really clunky:
my $yearString = YearArrayToString(@yearArray); sub YearArrayToString { my @years = @_; my $string = $years[0]; my $lastYear = $years[0]; if ($#years < 1) { return $string; } my $yearNum = 1; while ($yearNum <= $#years) { if ($lastYear+1 == $years[$yearNum]) {<br> while (($yearNum <= $#years) and ($lastYear+1 == $years[$y +earNum])) { $lastYear = $years[$yearNum]; $yearNum++; } $string = $string."-".$lastYear; } else { $string = $string.", ".@years[$yearNum]; $lastYear = $years[$yearNum]; } if ($years[$yearNum] == $lastYear) { $yearNum++; } } return $string; }
Can you show me some tricks that would make this better . . . and shorter?

Replies are listed 'Best First'.
Re: How do I easily turn a year array into a string
by kyle (Abbot) on Mar 03, 2009 at 22:52 UTC
Re: How do I easily turn a year array into a string
by Fletch (Bishop) on Mar 03, 2009 at 22:56 UTC

    Set::IntSpan seems to stringify to the right thing from your list.

    DB<5> x "" . Set::IntSpan->new( @yearArray ); + 0 '1992,1994-1995,1997-2000,2002,2004-2008'

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re: How do I easily turn a year array into a string
by AnomalousMonk (Archbishop) on Mar 04, 2009 at 00:45 UTC
    The Set::IntSpan approach is very neat, elegant and maintainable.

    However, if you want to roll your own, something like this might do the trick:

    >perl -wMstrict -le "my @yrs = @ARGV ? shift @ARGV : (); for my $yr (@ARGV) { $yrs[-1] =~ m{ (\d+) \z }xms; next if $yr - $1 != 1 and push @yrs, $yr; $yrs[-1] =~ s{ (?: - \d+)? \z }{-$yr}xms; } print join q{, }, @yrs; " 1992 1994 1995 1997 1998 1999 2000 2002 2004 2005 2006 2007 2008 2008 2007 2007 2008 2009 1992, 1994-1995, 1997-2000, 2002, 2004-2008, 2008, 2007, 2007-2009
    (Note: this does only minimal data validation.)

    Update: Fixed original statement  my @yrs = shift @ARGV if @ARGV; creating lexical array because such a creation should not be conditional, only its initialization.

Formatting note ~ Re: How do I easily turn a year array into a string
by Lawliet (Curate) on Mar 03, 2009 at 23:01 UTC

    You don't need <br>'s while between <code></code> tags. That is the beauty of them--they preserve your formatting. :)

    And you didn't even know bears could type.

Re: How do I easily turn a year array into a string
by johngg (Canon) on Mar 04, 2009 at 08:18 UTC

    Here is a different approach using join and a couple of regular expressions. If the array was not already sorted you could just insert a sort { $a <=> $b } into the join line.

    use strict; use warnings; my @yrArr = ( 1992, 1994, 1995, 1997, 1998, 1999, 2000, 2002, 2004, 2005, 2006, 2007, 2008, ); my $yrStr = join q{, }, @yrArr; $yrStr =~ s{(\d+), (?=(\d+))}{ $2 - $1 == 1 ? qq{$1-} : qq{$1, } }eg; $yrStr =~ s{(-\d+)+(?=-)}{}g; print qq{$yrStr\n};

    The output.

    1992, 1994-1995, 1997-2000, 2002, 2004-2008

    I hope this is useful.

    Cheers,

    JohnGG

Re: How do I easily turn a year array into a string
by eye (Chaplain) on Mar 04, 2009 at 07:30 UTC
    Just to be different (and because I don't like two element ranges):
    #!/usr/bin/perl my(@yearArray) = (1992, 1994, 1995, 1997, 1998, 1999, 2000, 2002, 2004 +, 2005, 2006, 2007, 2008); my($anchor) = shift(@yearArray); my(@out) = $anchor; while (@yearArray > 1) { my $tmp = shift(@yearArray); push(@out, ($yearArray[0] == $anchor + 2 ? '-' : $tmp)); $anchor = $tmp; } push(@out, @yearArray); my $out = join(', ', @out); $out =~ s/(, -)+, /-/g; print $out, "\n";

    This assumes that each element of @yearArray is numeric and that it is sorted in ascending order.