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

ok, i'm trying to write a subroutine that will take a numerically sorted array of numbers, and convert any series of 3 or more numbers that incrememnt one by one (ex: 1,2,3 or 926,927,928) and convert them to a string representing a range (ex: 1-3 or 926-928). ive been trying to figure out how to get this to work, but ive about driven myself out of my gourd and i still dont have a working routine...here's an example array:

1,2,8,9,10,11,12,43,66,109,121,122,123,657

and heres what it would look like afterbeing processed by the subroutine:

1,2,8-12,43,66,109,121-123,657

any help is appreciated

Edited 2003-03-19 by mirod: changed the title

  • Comment on Number lists to number ranges (was: my head is reeling...)

Replies are listed 'Best First'.
Re: my head is reeling...
by zengargoyle (Deacon) on Mar 18, 2003 at 23:53 UTC

    Set::IntSpan

    perl -e 'use Set::IntSpan;print Set::IntSpan->new(@ARGV)->run_list,$/' + "1,2,8,9,10,11,12,43,66,109,121,122,123,657" 1-2,8-12,43,66,109,121-123,657
Re: my head is reeling...
by particle (Vicar) on Mar 18, 2003 at 23:53 UTC
Re: my head is reeling...
by BrowserUk (Patriarch) on Mar 19, 2003 at 00:06 UTC

    There are several solutions to this problem in the thread starting at Humanized lists of numbers including an amazing regex.


    Examine what is said, not who speaks.
    1) When a distinguished but elderly scientist states that something is possible, he is almost certainly right. When he states that something is impossible, he is very probably wrong.
    2) The only way of discovering the limits of the possible is to venture a little way past them into the impossible
    3) Any sufficiently advanced technology is indistinguishable from magic.
    Arthur C. Clarke.
Re: Number lists to number ranges (was: my head is reeling...)
by shotgunefx (Parson) on Mar 19, 2003 at 15:32 UTC
Re: Number lists to number ranges (was: my head is reeling...)
by JamesNewman (Initiate) on Mar 19, 2003 at 18:22 UTC
    This is my first post so I apologise if its not upto scratch but here is a little something I put together which does what you want (I think).
    @start = (1,2,8,9,10,11,12,43,66,109,121,122,123,657); @queue = (); @output = (); print 'start :: ' , join(',',@start) , "\n"; foreach (@start) { if( ($_ - $queue[-1]) == 1 ) { # part of sequence push @queue, $_; } else { # store sequence push @output , (@queue > 2) ? $queue[0] . '-' . $queue[-1] : @ +queue; @queue = ($_); } } push @output , (@queue > 3) ? $queue[0] . '-' . $queue[-1] : join( ',' + , @queue ); print 'Expected :: 1,2,8-12,43,66,109,121-123,657' , "\n"; print 'End :: ' , join(',', @output);
    returns
    start :: 1,2,8,9,10,11,12,43,66,109,121,122,123,657 Expected :: 1,2,8-12,43,66,109,121-123,657 End :: 1,2,8-12,43,66,109,121-123,657
    Hope this helps.