Reputation: 169
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
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;
$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
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