Re: Array Comparison
by chromatic (Archbishop) on Dec 22, 2003 at 18:32 UTC
|
That nested loop is the killer. How about a hash? The following code is untested and unoptimized but performs better algorithmically:
my %exclude;
@exclude{ @exclude } = ();
my @cleaned = grep { exists $exclude{ $_ } ? () : $_ } @words;
Update: Yep, I confused grep with map in my pre-breakfast haste. That should rather be:
my @cleaned = grep { ! exists $exclude{ $_ } } @words; | [reply] [Watch: Dir/Any] [d/l] [select] |
|
my @cleaned = grep { not exists $exclude{$_} } @words;
Grep returns the original value for every element for which the expression returns true. Your ternary operator would be useful in map, but not here.
The PerlMonk tr/// Advocate
| [reply] [Watch: Dir/Any] [d/l] |
|
| [reply] [Watch: Dir/Any] |
|
Re: Array Comparison
by Ovid (Cardinal) on Dec 22, 2003 at 18:37 UTC
|
my @words = qw(foo bar baz quux Ovid);
my @exclude = qw(bar Ovid);
my %bad_words;
@bad_words{@exclude} = @words[@exclude];
@words = grep { ! exists $bad_words{$_} } @words;
| [reply] [Watch: Dir/Any] [d/l] |
Re: Array Comparison
by jZed (Prior) on Dec 22, 2003 at 18:41 UTC
|
@x = qw (1 2 3);
@y = qw (3 4 5);
my %v = map {$_=>1} @x;
my %w = map {$_=>1} @y;
for (@x,@y) { push @z,$_ if $v{$_} and !$w{$_} }
print (@z);
| [reply] [Watch: Dir/Any] [d/l] |
Re: Array Comparison
by Roy Johnson (Monsignor) on Dec 22, 2003 at 19:00 UTC
|
Your code does several things more than you describe. In addition to removing (case-insensitive) duplicates, it also has some other criteria for elimination, which should not be inside the foreach.
To duplicate your code functionally, we have to:
- Remove non-words (you missed a closing / in that pattern, by the way)
- Remove words shorter than 4 chars
- Remove words that appear more than once (your technique suggests that the list is sorted)
- Remove words that appear in @exclude
Ok, here we go!
# given @words and @exclude
my %seen;
@seen{@exclude} = (1) x @exclude;
@words = grep {
(! /\W/) and (length() >= 4) and ($seen{$_}++ == 0)
} @words;
We pre-load %seen with a flag for each word in @exclude. Then, as we're looking through @words itself, we mark each element as seen as well.
The PerlMonk tr/// Advocate
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
| [reply] [Watch: Dir/Any] |
Re: Array Comparison
by Not_a_Number (Prior) on Dec 22, 2003 at 20:11 UTC
|
To solve your case problem, try this:
use strict;
use warnings;
my @words = qw ( a ants cats cats dogs DOGS rabbits r@bbits turtles wa
+rthogs );
my @exclude = qw ( ants Turtles WARTHOGS );
my %exclude = map { lc $_ => '1' } @exclude;
for ( @words ) {
next if /\W/
or length $_ < 4
or $exclude{lc $_}++;
print "$_\n";
}
dave | [reply] [Watch: Dir/Any] [d/l] |
|
Actually, @words and @exclude are generated by reading outside sources. I just dropped the lc() right where the data is being read and it works just fine. Thank you for the suggestion though.
| [reply] [Watch: Dir/Any] |
|
Actually, @words and @exclude are generated by reading outside sources.
Well, yeah, that's what I assumed. I just added those arrays for testing. I even assumed that you might not have any control over the 'outside sources', which is why I did the lc() stuff in my snippet :-)
dave
| [reply] [Watch: Dir/Any] [d/l] |
Re: Array Comparison
by duff (Parson) on Dec 22, 2003 at 18:43 UTC
|
| [reply] [Watch: Dir/Any] |
|
No, it's not the intersection I want. And the FAQ doesn't give me the answer I'm looking for either.
What I need is array 1, minus any elements it has in common with array 2, and the comparison has to be case insensitive.
Your suggestion does not point to that kind of solution.
| [reply] [Watch: Dir/Any] |
Re: Array Comparison
by thraxil (Prior) on Dec 22, 2003 at 23:15 UTC
|
| [reply] [Watch: Dir/Any] |
|
Darn right it is. Wow, I had no idea. But now I do know the answer to that question, how and why. So, that's one point for me toward getting that job, whatever it is. Too bad I'm happy where I am right now.
| [reply] [Watch: Dir/Any] |