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

Before I went to bed last night I had a thought on Perl (happens every night :) ). My family has a cell phone plan and they have 4 different phone numbers and they're consecutive: (the last 4 digits are) 0802,0803,0804,0805.

I spent the day wondering how they can do that when people request "I want X phone numbers and I want them consecutive.". How could you have a program that asks for the number of numbers you want back from a list that are consecutive phone numbers (or ANY numbers since this isn't something that will be applied, it's just an interesting thing I was wondering) and display then for you?

my @array = (1,5,6,7,8,55,63,77,89,103,104,105,106,200,215,554);

Replies are listed 'Best First'.
Re: Consecutive number checking
by Zaxo (Archbishop) on Jul 04, 2004 at 06:51 UTC

    The .. (flip-flop) operator is handy for tests like this. In scalar context it first evaluates true when its left hand side becomes true, then remains true until the right hand side becomes true.

    my @array = (1,5,6,7,8,55,63,77,89,103,104,105,106,200,215,554); my @runs = @array[ grep { $array[$_+1] == 1+$array[$_] .. $array[$_+1] != 1+$array[$_] } 0..$#array ]; print "@runs",$/;
    The assignment is from a slice of the original @array, with grep selecting which indexes are to appear.

    That gives an array containing only runs, but there are more than one. As an exercise, try to split them up to get an array of arrays, each consecutive.

    After Compline,
    Zaxo

Re: Consecutive number checking
by gaal (Parson) on Jul 04, 2004 at 06:25 UTC

    Assuming the list of number is sorted, and contains no duplicates, you can tell if a "streak" occurs just by peeking ahead.

    for (my $i = 0; $i < @array - $streak_len; $i++) { print "$array[$i] .. " . $array[$i] + $streak_len . "\n" if $array[$i+$streak_len] == $array[$i] + $streak_len; }

    The disadvantage with this method is that it (a) reports overlapping streaks and (b) doesn't maximize streaks. (A) is easy to fix; when you find a streak, increment the index immediately by $streak_len.

Re: Consecutive number checking
by beable (Friar) on Jul 04, 2004 at 06:15 UTC
    Use a hash.
    #!/usr/bin/perl use strict; use warnings; my @array = (1,5,6,7,8,55,63,77,89,103,104,105,106,200,215,554); my %free_numbers = map {$_ => 1} @array; for my $number (@array) { my $ok = 1; for (my $i = 0; $i < 4; $i++) { if (! exists $free_numbers{$number + $i}) { $ok = 0; last; } } if ($ok) { print "found consecutive numbers: "; for (my $i = 0; $i < 4; $i++) { print $number + $i, " "; delete $free_numbers{$number + $i}; } print "\n"; } } __END__ found consecutive numbers: 5 6 7 8 found consecutive numbers: 103 104 105 106
Re: Consecutive number checking
by davido (Cardinal) on Jul 04, 2004 at 06:55 UTC

    This is quick-n-dirty, and works just fine...

    use strict; use warnings; my @array = (1,5,6,7,8,55,63,77,89,103,104,105,106,200,215,554); local $, = ', '; print sort { $a <=> $b } keys %{ { map { ( $array[ $_ ] == $array[ $_ + 1 ] - 1 ) ? ( $array[ $_ ] => 0, $array[ $_ + 1 ] => 0 ) : () } 0 .. $#array - 1 } };

    It does assume that @array is pre-sorted, and contains no duplicates. I was trying to come up with a regexp solution but gave up after confusing myself with (??{...}) constructs. ;) ...Enjoy.

    Updated: Discarded unnecessary use of a named hash. ;)


    Dave

Re: Consecutive number checking
by Anonymous Monk on Jul 04, 2004 at 16:35 UTC
    The module Set::IntSpan will do this.
    #!/usr/bin/perl use strict; use warnings; use Set::IntSpan; my @array = (1,5,6,7,8,55,63,77,89,103,104,105,106,200,215,554); my $set = Set::IntSpan->new(join ",", @array); my $run = $set->run_list; print $run; *** Output 1,5-8,55,63,77,89,103-106,200,215,554