[Date Prev][Date Next][Thread Prev][Thread Next] [Search] [Date Index] [Thread Index]

Re: [MacPerl] find value in array



At 6:08 PM 10/15/00, Bart Lateur wrote:
>On Sun, 15 Oct 2000 09:58:21 -0400, Ronald J Kimball wrote:
>>>  Bruce Van Allen wrote:
>>>  There's nothing quite as simple as that, but you can collapse the
>>>  array into a string and check for a pattern match:
>>>
>>>  if (join('', @list) =~ /$value/) {
>>>     # do stuff
>>>  }
>>>
>>>  HTH
>>
>>What if /$value/ could match the end of one element and the beginning of
>>the next?
>
>What if it can match the middle of a string? For example, "ap" in
>"pineapple"? What if $value contains a metacharacter?
>
>>@list = qw/ house fish flower train bowl apple /;
>>$value = 'rainbow';
>>
>>@join("\0", @list) would avoid that problem, as long as $value can't match
>>a substring containing a null character.
>

OK, a join character could be chosen that is not expected in the data:

my $sep = '~';  # or some other character not expected in the data

if (join($sep, @list) =~ /$sep$value$sep/) {
   # do stuff
   print "$value is in \@list.\n"
}

# Now, to provide the index to the found item in the array,
# count the $seps using tr/// (but remember tr works with no interpolation):

if (join($sep, @list) =~ /^(.*$sep$value)$sep/) {
     my $chunk = $1;    # $1 is what's matched by .*$sep$value
     $index = ($chunk =~ tr/~/~/);  # have to use the literal join character
     # now, do stuff with $list[$index]
     print "$value is item #", $index+1, " in \@list.\n"
}

The above examples don't cover all cases ($value in the first or last 
position of the list).

Here's a subroutine that will work for all cases as long as the 
character '~' isn't expected in the data:

sub inlist {
   my ($value, @list) = @_;
   $_ = join('~', @list);
   return unless /^($value)~/ || /^(.*~$value)~/ || /^(.*~$value)$/;
   my $chunk = $1;
   \($chunk =~ tr/~/~/)
}

Can the pattern matching could be optimized? I used the || syntax to 
be sure to get the right thing in $1.

The array index number is returned via a reference, so that if $value 
is the first item in the list, its index of 0 won't fail a truth 
test. Just dereference it to use the index. E.g., $list[$$index_ref]

if ($index_ref = inlist($value, @list)) {
     print "$value is item #", $$index_ref+1, " in \@list.\n"
}

If you only want the truth test, then the syntax is close to the AppleScript:

if inlist(($value, @list) {
    # do stuff
}

The other suggestions used map and grep, but those are really foreach 
turned inside out. map and grep don't have the attribute that foreach 
has of being able to bail from the iteration using last as soon as 
$value is found (if it is), so I'd suspect they are less optimal than 
foreach :-).

Go at it, Ronald and Bart ;-).

1;



- Bruce

__Bruce_Van_Allen___bva@cruzio.com__Santa_Cruz_CA__

# ===== Want to unsubscribe from this list?
# ===== Send mail with body "unsubscribe" to macperl-request@macperl.org