very empty has asked for the wisdom of the Perl Monks concerning the following question:

Hi monks!
I have an array and want to do something on every two succeding elements (its already sorted by a fancy sortfunction) At this moment I use the following ugly code

my $oldelem=0 # which cannot occur. foreach $elem (@elements) { do_something_with($oldelem,$elem) unless $oldelem==0; $oldelem=$elem; }

Is there any better way to do it?

Is there any way, to do this for n elements instead of two?

Regards...

Replies are listed 'Best First'.
Re: Traversing succeding sets of an array
by thelenm (Vicar) on May 14, 2002 at 15:42 UTC
    This may be one of those cases where an incremented index variable is useful:
    for my $i (0..$#elements-1) { do_something_with($elements[$i],$elements[$i+1]); }
Re: Traversing succeding sets of an array
by broquaint (Abbot) on May 14, 2002 at 15:34 UTC
    You could take advantage of hashes
    my %hash; push @{$hash{$_}}, $_ for @elements; foreach (keys %hash) { # gets passed an array reference, deref if you so desire do_something_with($hash{$_}) if scalar @{$hash{$_}} > 0; }
    Looks like you're dirtying your arguments there, maybe you want to have it return modified versions of the arguments e.g
    my @data; foreach (keys %hash) { push @data, do_something_with($hash{$_}) if scalar @{$hash{$_}} > 0; }
    Or maybe you have a perfectly valid reason for doing what you're doing like logging the sets to a file.

    Better yet I could actually answer your question ...

    my @elems = qw(foo bar baz quux ichi ni san shi go roku hachi); my $set = 3; while(scalar @elems) { do_something_with(splice(@elems, 0, $set)); }
    This however has the unfortunate side of effect of erasing the contents of the array, but does the job.
    HTH

    _________
    broquaint

    update: the penny dropped ...

Re: Traversing succeding sets of an array
by bmcatt (Friar) on May 14, 2002 at 15:44 UTC
    What about something like this?
    do_something_with($elements[$_-1], $elements[$_]) foreach (1 .. $#elements);
Re: Traversing succeding sets of an array
by strat (Canon) on May 14, 2002 at 15:40 UTC
    Maybe splice is your friend:

    my $elementsToGet = 2; # how many elements shell be in @sublist my @newElements = @elements; while (my @subList = splice(@newElements, 0, $elementsToGet)) { # do something with @subList } # while Beware that @newElements might be empty after the while...
    or, with a counter:
    for (my $i=0; $i<=$#elements; $i+=2) { # do something with $elements[$i] and $elements[$i+1] } # for
    I haven't tested these codes.

    Best regards,
    perl -le "s==*F=e=>y~\*martinF~stronat~=>s~[^\w]~~g=>chop,print"

      I do not have a even-sized list and I need to have to do also to do something with  ($elements[$i=2*$j-1],$elements[$i+1])
Re: Traversing succeding sets of an array
by Util (Priest) on May 14, 2002 at 16:06 UTC

    This works for $n between 1 and the number of elements, inclusive.
    It takes advantage of array slices when calling the subroutine.

    sub do_something_with { print "@_\n"; } my @elements = qw( a b c d e f g ); my $n = 2; for my $i ($n-1 .. $#elements) { do_something_with(@elements[($i-($n-1))..$i]); }

    $n = 2 produces:

    a b c b c d c d e d e f e f g

    $n = 4 produces:

    a b c d b c d e c d e f d e f g

Re: Traversing succeding sets of an array
by boo_radley (Parson) on May 14, 2002 at 16:42 UTC
    Yet another way, that works for exactly 2 elements.
    my @foo = qw (one two three four five six seven eight nine ten); while ($c <$#foo){ ($s,$a)= @foo[$c++ .. ++$c+1]; print "$s $a\n"; }