jbord39
jbord39

Reputation: 169

perl array processing at once

I have an array with many many entries like:

"a->b->c->x->n"
"something->something1->somethingelse"

I want to extract all odd elements from the array at once and make a hash with their unique values, like:

%s = {
  "b" => '1'  
  #the values don't matter too much, they could be # occurences, I am going to use keys %s.
  "x" => '1'
  "something1" => '1'
}

Currently I am doing this in a couple steps but just looping through the array is taking a substantial amount of time so I think there is someway to do it better.

my ( @odds, @evens );
foreach (@arr) {
  my $i = 0;
  push @{ $i++ % 2 ? \@odds : \@evens }, $_ for split /->/, $_;
}
%s = map {  $_ => '1'; } @odds;

Any suggestions to process the whole array at once?

Upvotes: 0

Views: 111

Answers (2)

Borodin
Borodin

Reputation: 126762

If you're interested in only those elements of the lists that have an odd index then a C-style for loop is the obvious choice

use strict;
use warnings 'all';

my @arr = ( "a->b->c->x->n", "something->something1->somethingelse" );

my %s;

for ( @arr ) {

    my @k = split /->/;

    for ( my $i = 1; $i < @k; $i += 2 ) {
        $s{ $k[$i] } = 1;
    }
}

use Data::Dumper;
print Dumper \%s;

output

$VAR1 = {
          'b' => 1,
          'x' => 1,
          'something1' => 1
        };

You may also want to consider a regex solution if the values between the -> are really as well-behaved as you describe. This assumes that the lists always contain an odd number of characters.

for ( @arr ) {
    $s{ $1 } = 1 while /->(\w+)->/g;
}

The result of this loop is identical to that of the previous code

Upvotes: 1

ikegami
ikegami

Reputation: 386561

Your request makes no sense. If you want to perform something to each element of the array, you will necessarily have to loop through every element of the array (whether for is used or not).

And I don't see anything in that code that would be slow (unless the OS started using virtual memory because you are running out of memory). It is wasteful to populate @evens and never use it.

The following is a cleaner version of your code. It's also faster (thanks to pairvalues and avoiding temporary storage), but it shouldn't be substantially so.

use List::Util qw( pairvalues );  # 1.29+

my %s;
for (@arr) {
   ++$s{$_} for pairvalues split /->/;
}

If you don't mind weird/ugly code, the following is even faster (if only marginally):

use List::Util qw( pairvalues );  # 1.29+

my %s;
for (@arr) {
   undef @s{ pairvalues split /->/ };
}

Upvotes: 3

Related Questions