Home > Archive > PERL Modules > April 2005 > Which module formats runs of integers a la 1, 4-7, 8, 10?
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
Which module formats runs of integers a la 1, 4-7, 8, 10?
|
|
| Ron Savage 2005-04-09, 3:56 am |
| =00
| |
| Jonathan Leffler 2005-04-09, 3:56 am |
| Ron Savage wrote:
> Which module formats runs of integers a la 1, 4-7, 8, 10?
Not sure - does it warrant a module? Also, I presume that the list
output should be 1,4-8,10 rather than listing 4-7 and 8 separately.
I have a piece of code which can readily be adapted to the job. The
original use is for formatting up the list of years when changes were
made (to a source file kept in RCS), suitable for use in a copyright
message.
#!/bin/perl -w
use strict;
my @values;
# Generate a list of numbers, discarding all non-digits
while (<> )
{
chomp;
next unless /\d/;
my(@nums) = split /\D+/, $_;
push @values, @nums;
}
# Sort the list numerically.
@values = sort { $a <=> $b } @values;
# Generate a list such as 1,4-8,10
my ($list, $old) = ("", shift @values);
foreach my $value (@values)
{
my $pad = ($value == $old+1) ? "-" : ",";
$list =~ s/-$old$// if ($value == $old+1);
$list .= "$pad$value";
$old = $value;
}
$list =~ s%^,%%; # Remove leading comma
print $list;
Have fun.
--
Jonathan Leffler #include <disclaimer.h>
Email: jleffler@earthlink.net, jleffler@us.ibm.com
Guardian of DBD::Informix v2005.01 -- http://dbi.perl.org/
| |
| Jonathan Leffler 2005-04-09, 3:56 am |
| Jonathan Leffler wrote:
> Ron Savage wrote:
>
> Not sure - does it warrant a module? Also, I presume that the list
> output should be 1,4-8,10 rather than listing 4-7 and 8 separately.
>
> I have a piece of code which can readily be adapted to the job. The
> original use is for formatting up the list of years when changes were
> made (to a source file kept in RCS), suitable for use in a copyright
> message.
Darn it - this doesn't handle empty lists or lists of one number properly.
> #!/bin/perl -w
>
> use strict;
> my @values;
>
> # Generate a list of numbers, discarding all non-digits
> while (<> )
> {
> chomp;
> next unless /\d/;
> my(@nums) = split /\D+/, $_;
> push @values, @nums;
> }
exit 0 if $#values < 0;
> # Sort the list numerically.
> @values = sort { $a <=> $b } @values;
>
> # Generate a list such as 1,4-8,10
> my ($list, $old) = ("", shift @values);
# Replace the above with...
my($old) = shift @values;
my($list) = "$old";
> foreach my $value (@values)
> {
> my $pad = ($value == $old+1) ? "-" : ",";
> $list =~ s/-$old$// if ($value == $old+1);
> $list .= "$pad$value";
> $old = $value;
> }
> $list =~ s%^,%%; # Remove leading comma
>
> print $list;
>
> Have fun.
>
--
Jonathan Leffler #include <disclaimer.h>
Email: jleffler@earthlink.net, jleffler@us.ibm.com
Guardian of DBD::Informix v2005.01 -- http://dbi.perl.org/
| |
| Jonathan Leffler 2005-04-09, 3:56 am |
| Jonathan Leffler wrote (correcting himself the first time):
> Jonathan Leffler wrote:
>
> Darn it - this doesn't handle empty lists or lists of one number properly.
Double bother. The original code used a hash to eliminate duplicates; I
didn't test the revised code on lists with duplicates. The embarassment.
This version has been tested on an empty file, on a file with a single
number, a file with no numbers, on itself, and on a pile of junk. On
itself, it produces the output: 0-2,4-10,50,2005
#!/bin/perl -w
#
# @(#)$Id: printlist.pl,v 1.2 2005/04/09 06:06:58 jleffler Exp $
#
# Convert numbers into appropriately grouped lists
# Eg: 1,4a6kk5x7x8,10 becomes 1,4-8,10
use strict;
my %values;
# Read values, ignoring non-digits except as number delimiters.
# Use hash to eliminate duplicates.
while (<> )
{
chomp;
foreach my $num (split /\D+/, $_)
{
next unless $num =~ /\d/;
$num =~ s/^0+(\d)/$1/o;
$values{$num} = 1;
}
}
# Convert to numerically sorted list
my @values = sort { $a <=> $b } keys %values;
# Exit if list is empty
exit 0 if $#values < 0;
# Format result
my ($old) = shift @values;
my ($list) = "$old";
foreach my $value (@values)
{
my $pad = ($value == $old+1) ? "-" : ",";
$list =~ s/-$old$// if ($value == $old+1);
$list .= "$pad$value";
$old = $value;
}
$list =~ s%^,%%; # Remove leading comma
print "$list\n";
The 'next unless' test in the reader loop eliminates empty strings. The
split expression eliminates other non-digits. It probably isn't optimal
but it does seem to work.
--
Jonathan Leffler #include <disclaimer.h>
Email: jleffler@earthlink.net, jleffler@us.ibm.com
Guardian of DBD::Informix v2005.01 -- http://dbi.perl.org/
| |
|
|
| Ron Savage 2005-04-10, 3:55 am |
| On Sat, 9 Apr 2005 21:01:28 +1000, Peter Scott wrote:
Hi Jonathan and Peter
Thanx for the replies.
I will have a play with Jonathan's code.
As for Set::IntSpan, I did read up on it before posting, but not carefully
enough. For some reason I thought it was not appropriate.
Sorry - I should have mentioned that up front.
| |
| Ron Savage 2005-04-10, 3:55 am |
| On Sat, 9 Apr 2005 21:01:28 +1000, Peter Scott wrote:
Hi Folks
Ahh, I see now. I had been reading up on Set::IntRange, and had not gotten=
to
Set::IntSpan :-(.
|
|
|
|
|