Re: Is list member
by ariels (Curate) on May 06, 2002 at 08:15 UTC
|
No, you cannot write a single function that will do both. You must have some notion of what "equality" means before you can write this function. Say we denote such equality (in English, not in Perl) with the symbol `~'. You'll need to decide e.g.
- '10' ~ 10?
- 'x10' ~ 0?
- '' ~ 0?
It's also not clear from your question if you want the same function to work for finding both numbers in a number list and strings in a string list, or if you'd also like it magically to "do the right thing" when searching for a string in a number list etc.
Consider what you want to do, and then replace your problematic comparison e.g. with one of these:
- "$_" eq "$item"
- 0+$_ == 0+$item
- The same, but <samp>local</samp>ly switching $^W off.
For an all-singing, all-dancing run-time customizable (and slower) solution, pass in a function to perform the comparison:
sub member(&@$) {
my ($eq, $array, $item) = @_;
for (@$array) {
return 1 if $eq->($_, $item)
}
return undef;
}
Finally, why are you trying to circumvent Perl's booleans? The use of things like $TRUE and $FALSE is a bad idea. First, builtins might not return these values, so you end up with 4 different values, and cannot do stuff like "return $a == $b" in the routine you pass to member. The values of TRUE and FALSE aren't going to change in the lifetime of your program; if they do, all your code will fall apart, so it doesn't matter. And note you're still using Perl's booleans, not yours:
... if ($_ eq $item)
should really test for truth, so it should be
... if ($_ eq $item) == $TRUE
which should really test for truth, so it should be
... if (($_ eq $item) != $FALSE) eq $TRUE
etc.
| [reply] [d/l] [select] |
Re: Is list member
by JayBonci (Curate) on May 06, 2002 at 09:08 UTC
|
Stringification is your friend. You can use double quotes to have any item thrown into string context. It won't matter if it's another string or not, such as:
#!/usr/bin/perl -w
use strict;
my @stuff = ("foo", 1, "3", "5", 8, "jerk", "bummer");
my $test = "1";
foreach(@stuff){
print "Found!\n" if ("$test" eq "$_");
}
Note tossing $test and $_ into strings solves all sorts of internal numerical <=> issues. I think it always comes up with the same string that you'd get as if you print'ed it. However, if you're looking for numerical equivalency (ie, you're passing in things like "0e0" and expecting it to match to it's equivalent), then you're probably out of luck. This is for ultra simple data sets. Just another way of thinking about it...
--jb
| [reply] [d/l] |
Re: Is list member
by erikharrison (Deacon) on May 06, 2002 at 08:17 UTC
|
Actually, that IS how you handle numeric values. Perl is absolutely typeless - meaning that it implicitly stringifies and numifies variables in the right context. Now, numification often gets you 0 which makes alot of things match where you want them not to. However, stringification will usually get matches properly, when comparing two numbers.
ps: Perl 6! $foo =~ @array
Cheers,
Erik
| [reply] [d/l] |
|
|
$ perl -e'$c="10e0";$d="1e1";print $c == $d,$/'
1
$ perl -e'$c="10e0";$d="1e1";print $c eq $d,$/'
$ perl -e'$c=10e0;$d=1e1;print $c eq $d,$/'
1
$ perl -e'$c=10e0;$d=1e1;print $c == $d,$/'
1
I think this question is best solved by redesigning it away.
After Compline, Zaxo
| [reply] [d/l] |
Grep ?..
by yodabjorn (Monk) on May 06, 2002 at 10:07 UTC
|
couldnt you use grep to do this ?
#!/usr/bin/perl -w
#
# quick test to match an item in an array
use strict;
my $match = shift ;
my @arr = qw( 2 3 4 5 6 7 foo foo12 12foo 1foo1) ;
print "match \n" if ( grep(/\b$match\b/, @arr) ) ;
1 as input will not match
foo as input will not match
2 as input matches!
works for me.. is this a bad way to go about it ? my regex may not be optimal. regex is not my strong point. I just got the book on it. It's next after "Data Munging with perl" | [reply] [d/l] |
|
|
| [reply] |
Re: Is list member
by hotshot (Prior) on May 06, 2002 at 07:55 UTC
|
Silly me, it's obvious how to do that, I'v just changed it too: sub isListMember {
my ($array, $item) = @_; # array ref, item
for (@{$array}) {
if (/^\d+$/) {
return $TRUE if ($_ == $item);
} else {
return $TRUE if ($_ eq $item);
}
}
$return $FALSE;
}
Is that the right way, or there's a better or correct one?
Thanks.
Hotshot | [reply] [d/l] |
|
|
| [reply] |