On Mon, Dec 17, 2001 at 01:19:43PM +0100, Kredler Stefan wrote: > I want to transform a sorted list into a compact list (if this is the > correct term). > e.g. my list is > > 9,11,12,13,14,23,25,26,27,50 and want to have something like > 9,11-14,23,25-27,50 (to pass on to a unix-command). > > Is there any module or function I can use to summarize or compact this?
Don't know. I decided that this was the sort of thing I shouldn't have any problem in writing, though, and ended up spending most of my lunch break on it. It seems to work for the sort of data you gave: void:chris~ % perl compact.pl 9 11 12 13 14 23 25 26 27 50 9,11-14,23,25-27,50 I'd be really interested to see if anyone can come up with a better way of doing this; one that doesn't have to keep state, or uses recursion. I'll bow down to anyone who can make a one-liner of it, naturally. Hope this helps - out of interest, what sort of UNIX command _needs_ a list like that instead of an explicit one? - ~C. void:chris~ % cat compact.pl #!/usr/bin/perl -w # Author: Chris Ball <[EMAIL PROTECTED]> # Function: Provide a 'compact list' for an array of numbers. # Also at: http://printf.net/compact.pl my @approx = @ARGV; my ($i, $inrange, $start, $end, $more); use strict; # Overview: # - Loop through the array. # - If the element after current matches (cur+1): # - Extend a range if we're in one. # - Set up a range if we aren't. # - If the element after current _isn't_ (cur+1): # - Mark/print the end of a range, or # - Print a number on its own if we weren't in a range. # - If the element after current just doesn't exist at all: # - Finish off a range or number tidily. map { # Loop through the array, using $_. my $cur = $approx[$_]; my $next = $approx[$_+1] if defined $approx[$_+1]; if ($next) { # Is there an array element after this one? if ($next != ($cur + 1)) { # If the next element _isn't_ current+1.. if ($inrange) { # If we're in a range, it needs to be finished. print "$start-$end,"; $inrange = 0; } else { # We're not in a range. print "$cur,"; } } else { # If the next array element is cur+1. if ($inrange) { # If we're already in a range, extend it by 1. $end++; } if (not $inrange) { # We're not in a range. Set start/end/inrange. $start = $approx[$_]; $end = $approx[$_+1]; $inrange = 1; } } } else { # It's the last element. Make things look tidy. if ($inrange) { print "$start-$end\n"; } else { print "$cur\n"; } } } 0..$#approx # -- end. -- Chris Ball E-mail: [EMAIL PROTECTED] Web Engineer Web : www.fast.no Fast Web Media Ltd Try : www.alltheweb.com 12th Floor Sunlight House, Quay Street, Manchester M3 3JZ, UK. -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]