in reply to Finding values position in array
You could also refer to the very complete Getting Matching Items From An Array.
At first I said, "of course GrandFather is right", but upon further testing the situation is not so clear. The optimizations in grep give it an edge over the C style for if you have to look approximately 1/2 way into the array. This did not surprise me as much as the poor performance of a binary search. ( code borrowed from Binary search). Though I think after struggling to coax grep to return a list value into a scalar context I would avoid that solution unless you really want multiple values returned.
oko1 gives an implementation of grep but I was thinking more something like: grep {$array[$_] eq $value} (0..$#array) as shown in the code below. Which, as I said, may be just quick enough.
#!/usr/bin/perl use Benchmark 'cmpthese'; use warnings; @array = ( 'a'..'zz' ); $value = 'mz'; my $res; my $position; print "for(): ".traditional(). "\tforeach: ".for_each(). "\tmap: ".maptohash(). "\tgrep_if: ".grep_if(). "\tbinary search: ".bin_search(). "\n"; cmpthese ( 1000, { for_loop => '$res = traditional()', map => '$res = maptohash()', for_each => '$res = for_each()', grep_if => '$res = grep_if()', bin_search => '$res = bin_search()', } ); sub traditional{ for ($position=0; $position <= $#array; $position++) { last if ($array[$position] eq $value); } return $position; } sub for_each{ for our $position ( 0..$#array ) { last if ($array[$position] eq $value) ; } return $position; } sub maptohash{ %indexed = map{ $array[$_], $_ } (0..$#array); return $indexed{$value}; } sub grep_if{ my @res = grep {$array[$_] eq $value} (0..$#array); return @res[0]; } sub bin_search { return BinSearch( $value, \&cmpFunc, \@array ); } sub BinSearch { my ($target, $cmp) = @_; my @array = @{$_[2]}; my $posmin = 0; my $posmax = $#array; return -0.5 if &$cmp (0, \@array, $target) > 0; return $#array + 0.5 if &$cmp ($#array, \@array, $target) < 0; while (1) { my $mid = int (($posmin + $posmax) / 2); my $result = &$cmp ($mid, \@array, $target); if ($result < 0) { $posmin = $posmax, next if $mid == $posmin && $posmax != $posmin; return $mid + 0.5 if $mid == $posmin; $posmin = $mid; } elsif ($result > 0) { $posmax = $posmin, next if $mid == $posmax && $posmax != $posmin; return $mid - 0.5 if $mid == $posmax; $posmax = $mid; } else { return $mid; } } } sub cmpFunc { my ($index, $arrayRef, $target) = @_; my $item = $$arrayRef[$index]; return $item cmp $target; } %perl foo.pl + [10:49pm] Scalar value @res[0] better written as $res[0] at foo.pl line 47. for(): 363 foreach: 363 map: 363 grep_if: 363 binary + search: 363 Rate map for_loop grep_if bin_search for_ea +ch map 200/s -- -69% -72% -81% -8 +8% for_loop 650/s 224% -- -8% -39% -6 +0% grep_if 707/s 253% 9% -- -33% -5 +7% bin_search 1058/s 428% 63% 50% -- -3 +6% for_each 1641/s 719% 153% 132% 55% +--
s//----->\t/;$~="JAPH";s//\r<$~~/;{s|~$~-|-~$~|||s |-$~~|$~~-|||s,<$~~,<~$~,,s,~$~>,$~~>,, $|=1,select$,,$,,$,,1e-1;print;redo}
|
---|
Replies are listed 'Best First'. | |
---|---|
Re^2: Finding values position in array
by Not_a_Number (Prior) on Apr 14, 2008 at 11:52 UTC | |
by starbolin (Hermit) on Apr 14, 2008 at 17:55 UTC | |
by starbolin (Hermit) on Apr 15, 2008 at 00:54 UTC |