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

Monks, I would like to test an array if it contains only elements from another array, and die if it contains an element not in the array. Ive tried this test code
#! /usr/bin/perl -w use strict; my @allowed = split '', 'abcdefghijklmno'; my %testHash; @testHash{@arg}=(); my @test = split '', 'acbbedfydaccd'; die "Unknown char! \n" unless exists $testHash{$_} for (@test); print "success!\n";
I get a syntax error at line 10 near }. For some reason it does not like the use of $_. Any suggestions? Thanks.

Replies are listed 'Best First'.
Re: checking array elements aginst another array
by holli (Abbot) on May 08, 2009 at 09:50 UTC
    Array::Diff


    holli

    When you're up to your ass in alligators, it's difficult to remember that your original purpose was to drain the swamp.
Re: checking array elements aginst another array
by johngg (Canon) on May 08, 2009 at 10:36 UTC

    You could use grep instead of a loop to filter the characters.

    use strict; use warnings; my %allowed = map { $_ => 1 } q{a} .. q{o}; my @testStrs = qw{ acbbedfydaccdtg abcde }; my @unknown = (); foreach my $testStr ( @testStrs ) { @unknown = grep { ! $allowed{ $_ } } split m{}, $testStr; print qq{String - $testStr: }, @unknown ? qq{Unknown characters found: @unknown\n} : qq{Success\n}; }

    The output.

    String - acbbedfydaccdtg: Unknown characters found: y t String - abcde: Success

    I hope this is of use.

    Cheers,

    JohnGG

Re: checking array elements aginst another array
by jethro (Monsignor) on May 08, 2009 at 09:47 UTC

    To make that work you have to construct a "simple statement" for the outer statement modifier (the for loop)

    do { die "Unknown char! \n" unless exists $testHash{$_} } for (@test);

    Read the paragraph 'Simple Statements' in perlsyn man page if you want to know more

Re: checking array elements aginst another array
by jettero (Monsignor) on May 08, 2009 at 10:05 UTC

    List::MoreUtils's pairwise() might be helpful for a similar kind of comparison too.

    -Paul

Re: checking array elements aginst another array
by Anonymous Monk on May 08, 2009 at 09:37 UTC
    You cannot have more than one statement modifier, and you can't make up syntaxt :)
    die "Unknown char! \n" unless exists $testHash{$_} for (@test);
    is better written as
    die "Unknown char! \n" unless grep { exists $testHash{$_} } @test;
      ... better written as
         die "Unknown char! \n" unless grep { exists $testHash{$_} } @test;
      This will only  die when none of the characters in the test string are 'known':
      >perl -wMstrict -le "my %testHash = map { $_ => 1 } 'a' .. 'j'; for my $str (@ARGV) { my @test = split '', $str; die qq{unknown char in '$str'} unless grep { exists $testHash{$_} } @test; print qq{'$str' ok}; } " abcd axyz xyz 'abcd' ok 'axyz' ok unknown char in 'xyz' at -e line 1.
      A better way to write this (assuming something like Array::Diff is not acceptable) might be:
          exists $testHash{$_} or die "Unknown char! \n" for @test;
Re: checking array elements aginst another array
by targetsmart (Curate) on May 08, 2009 at 09:37 UTC
    use one modifier in a statement to be clear
    see here

    Vivek
    -- In accordance with the prarabdha of each, the One whose function it is to ordain makes each to act. What will not happen will never happen, whatever effort one may put forth. And what will happen will not fail to happen, however much one may seek to prevent it. This is certain. The part of wisdom therefore is to stay quiet.
Re: checking array elements aginst another array
by Marshall (Canon) on May 08, 2009 at 14:17 UTC
    I would just go ahead and make this an explicit loop like below rather than messing with the do{} construction. Also your example just has letters. If that's what you really have instead of multi-character tokens, there is an easier way to do this with tr as shown below.
    #!/usr/bin/perl -w use strict; $|=1; #autoflush so die comes out in right printout order #(after the prints) my @allowed = split '', 'abcdefghijklmno'; my %testHash; @testHash{@allowed}=(); my @test = split '', 'acbbedfydaccd'; #die "Unknown char! \n" unless exists $testHash{$_} for (@test); foreach (@test) { print "Unknown char! $_ \n" unless exists($testHash{$_}); } ####### another way ######### ###### use tr to count characters not in the set of allowed my $test = 'acbbedfydaccdy'; my $errors = $test =~ tr/abcdefghijklmno//c; print "\nerrors = $errors\n"; print "test=$test\n"; die "died Unknown character\n" if ( $test=~tr/abcdefghijklmno//c ); __END__ Unknown char! y errors = 2 test=acbbedfydaccdy # I added another y at end for testing died Unknown character
Re: checking array elements aginst another array
by bichonfrise74 (Vicar) on May 08, 2009 at 22:35 UTC
    Do you want to try something like this?
    #!/usr/bin/perl use strict; my @test_arrays = qw( a e b c ); my @check_arrays = qw( b a ); foreach my $i (@test_arrays) { print "Not found - $i\n" if ( !grep /$i/, @check_arrays ); }