Every other

Philip Potter philip.g.potter at gmail.com
Fri Oct 30 10:14:14 GMT 2009


2009/10/30 Mark Fowler <mark at twoshortplanks.com>:
> Hello,
>
> I have in the past coded things to only discover later that someone
> else has already written what I have toiled away on, only better.  So
> this time, I'm asking the experts[1] first.
>
> I have an array in Perl 5 [2].  I want *every* *other* element from
> it.  There is, of course, more than one way to do it:
>
> my @new;
> foreach (my $i = 0; $i < @old; $i++) {
>  push @new, $old[ $i ];
> }

ew, C-style for loops :( Also, I think you meant $i+=2

> Or
>
> my $i;
> my @new = grep { $i = !$i } @old;

Is grep guaranteed to execute the code block on elements sequentially?
Might it (if not now, possibly in future) dispatch different blocks to
different processing elements, which would kinda screw this up?

Actually this is one thing that annoys me about Perl -- there doesn't
seem to be a definitive standard to say whether these guarantees are
cast-iron or whether they might change with new versions of perl. Or
if there is, I haven't seen one. I miss the certainty of the C
standard...

> What I would prefer is this:
>
> my @new = every_other @old;
>
> Which I guess could be generalised like so:
>
> i.e.
>
> everyother @array;
> everyother @array, $offset;
> everyother @array, $offset, $take_how_many;
> everyother @array, $offset, $take_how_many, $skip_how_many;

That syntax requires prototypes, which in general you should avoid.

> Ideally this would be a utility in List::MoreUtils or suchlike, but
> it's not.  Ideally it'd be implemented in C as well as in Perl so that
> it doesn't burn ops for such a simple idea.
>
> Before I get going with the coding, does anyone know of anything else
> that can do this?

If the array is sorted and has no duplicate values, and runtime costs
haven't been demonstrated to be an issue, then what about:

my %hash = @array;
my @array1 = sort keys %hash;
my @array2 = sort values %hash;

;)

Standard are-you-sure questions:

Is there a reason you are so concerned with it being as fast as
possible? Are you solving a problem which needs to be solved? Do you
have a project in which the cost of taking every other element has
been profiled and measured and shown to be significant?

Why do you need to take every other element of an array in the first
place? Could you have rewritten your code or redesigned your data
structures so that the data you want is already in the form you want
it? If you need the array just to loop through it, why not do
something like:

while (($x) = splice @a, 0, 2) { # all parens are necessary
    # loop here
}

> [2] There's very nice syntax for this in Perl 6, isn't there?  I'm not
> using that language yet.

There's a for loop syntax which allows you to iterate over every other
element easily:
http://perlcabal.org/syn/Differences.html#foreach_becomes_for

I'm not sure there's a nice syntax to just create the array.

Phil



More information about the london.pm mailing list