reluctant_techie has asked for the wisdom of the Perl Monks concerning the following question:

I need to compare two arrays and then execute addition code depending on whether or not there is a value in @b that does not have a match in @a.

My code thus far is

my @SupportedPTs = ('Accounting','Dnd','Essay','FITB','Hotspot','Match +ing','MC','Narrative','SingleAnswer','SelfGradingGeneric','Sketch','S +tatic','TF'); my @ProblemTypes = ('Accounting','Dnd','test'); my %seen = (); foreach (@ProblemTypes) { $seen{$_} = 1; } if (grep ($seen{$_}, @SupportedPTs) ) { print "Supported\n"; } else { print "Unsupported\n"; }
This program successfully compares the arrays but returns "Supported" if there is any match in @SupportedPTs for a value in @ProblemTypes. I am having trouble thinking this through. Any help would be appreciated.

Replies are listed 'Best First'.
Re: Comparing arrays and returning false if an exception is found
by oko1 (Deacon) on Apr 16, 2008 at 23:26 UTC

    It's an FAQ. Take a look at perldoc -q intersect.

    
    -- 
    Human history becomes more and more a race between education and catastrophe. -- HG Wells
    
Re: Comparing arrays and returning false if an exception is found
by ysth (Canon) on Apr 17, 2008 at 00:18 UTC
    if (grep($seen{$_}, @SupportedPTs) )
    translates into English as: if any (non-zero returned by grep) of @SupportedPTs are keys in %seen (with corresponding true values).

    You want "if any of @SupportedPTs are NOT keys in %seen":

    if (grep(! $seen{$_}, @SupportedPTs) )
    (with your if and else blocks reversed) or perhaps "if none (zero returned by grep) of @SupportedPTS are NOT keys in %seen":
    if (! grep(! $seen{$_}, @SupportedPTs) )
    with the if and else blocks unchanged.
Re: Comparing arrays and returning false if an exception is found
by pc88mxer (Vicar) on Apr 16, 2008 at 23:21 UTC
    Basically you need to perform a set difference operation.
    my %seen = (); $seen{$_} = 1 for (@ProblemTypes); delete $seen{$_} for (@SupportedPTs); if (%seen) { # some element in @ProblemTypes is not in @SupportedPTs print "elements in ProblemTypes but not in SupportedPTs: ", join(' ' +, keys %seen), "\n"; }
Re: Comparing arrays and returning false if an exception is found
by toolic (Bishop) on Apr 16, 2008 at 23:37 UTC
    If you are wondering why your code returns "Supported", it is because both arrays contain the 2 strings: "Accounting" and "Dnd". According to the documentation, your grep returns the value of 2, which is true in the if statement:
    In scalar context, returns the number of times the expression was true.

    It becomes more obvious if you add these lines of debug code:

    my $num = grep ($seen{$_}, @SupportedPTs); print "num=$num\n";

    On another note, you could save yourself some typing by using the qw operator:

    my @ProblemTypes = qw(Accounting Dnd test);
Re: Comparing arrays and returning false if an exception is found
by citromatik (Curate) on Apr 17, 2008 at 11:48 UTC

    I think that grep is not the right tool for doing what you want. If I am right you want to iterate over all the items in array a and see if they are present in array b. Try the following:

    my @SupportedPTs = ('Accounting','Dnd','Essay','FITB','Hotspot','Match +ing','MC','Narrative','SingleAnswer','SelfGradingGeneric','Sketch','S +tatic','TF'); my @ProblemTypes = ('Accounting','Dnd','test'); my %seen = (); foreach (@ProblemTypes) { $seen{$_} = 1; } for (@SupportedPTs){ if (! $seen{$_}){ print "$_ is supported\n"; } else { print "$_ is not supported\n"; } }

    Outputs:

    Accounting is not supported Dnd is not supported Essay is supported FITB is supported Hotspot is supported Matching is supported MC is supported Narrative is supported SingleAnswer is supported SelfGradingGeneric is supported Sketch is supported Static is supported TF is supported

    Update:If you want to use grep (a solution less efficient than the previous), you don't need the temporary hash:

    for my $sPT (@SupportedPTs){ if (! grep{/$sPT/} @ProblemTypes){ print "$sPT is supported\n"; } else { print "$sPT is not supported\n"; } }

    Hope this helps,

    citromatik

      I read the "I need to compare two arrays and then execute addition code depending on whether or not there is a value in @b that does not have a match in @a." as wanting an if statement testing whether all the values in @b are in @a, not an if statement for each element in the array. It could have been meant the other way, but given the code posted, I think it unlikely.