For Programmers: Free Programming Magazines  


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/
Peter Scott

2005-04-09, 8:56 am

Set::IntSpan

--
Peter Scott
http://www.perlmedic.com/
http://www.perldebugged.com/

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 :-(.



Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com