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

I have two lists of files. File list A is a list of files that have been transferred. File list B is a list of all files in a given directory. What I want to find is an item from list B that does not exist anywhere in list A. I just can't quite get my head around how to approach the problem.

@rray1=('one','red','orange','brown','green','blue','scarlett','fourte +en'); @rray2=('red','orange','yellow','green','blue','indigo','violet'); foreach my $check (<@rray1>) { foreach my $item (<@rray2>) { if ($check ne $item) { <do something> } }#close foreach
The problem with this approach is pretty obvious: 'one' does not match anything in the second list, which would be what I want. However, 'red' matches 'red' but also shows as not matched on everything else. Basically, I think what I want is to find a string wherever it is in an array. I've tried playing with hashes (also grep) on this to see if the solution might be in that direction, but I'm at a loss as to where to go from here. I just need a prod in the right direction, not a full-blown solution.

thanks

Replies are listed 'Best First'.
Re: Match string in array
by JediWizard (Deacon) on Oct 03, 2005 at 19:10 UTC

    my(%listA) =(); @listA{'one','red','orange','brown','green','blue','scarlett','fourte +en'} = (); my(@listB) = ('red','orange','yellow','green','blue','indigo','violet' +); foreach my $check (@listB){ print "$check\n" if(! exists($listA{$check})); } __END__ # Output: yellow indigo violet

    They say that time changes things, but you actually have to change them yourself.

    —Andy Warhol

      ++ Thanks, thats exactly what I needed.
Re: Match string in array
by ikegami (Patriarch) on Oct 03, 2005 at 19:46 UTC

    Since noone mentioned it so far,
    foreach my $check (<@rray1>) {
    is very dangerous and inefficient. You should use
    foreach my $check (@rray1) {
    instead.

    <@rray1>
    is equivalent to
    glob(join($", @rray1))
    It is dangerous because a number of characters are special to glob (including spaces).

Re: Match string in array
by Skeeve (Parson) on Oct 03, 2005 at 19:54 UTC
    my(@rray1)=('one','red','orange','brown','green','blue','scarlett','fo +urteen'); my(@rray2)=('red','orange','yellow','green','blue','indigo','violet'); # If I got something like this, I usually do it this way: # 1. Make a hash out of the array you want to check: my (%hash); @hash{@rray1}= (); # 2. Delete everything from that hash that's in @rray2 delete @hash{@rray2}; # 3. What's left over is what you're searching print join("\n", keys %hash),"\n";

    $\=~s;s*.*;q^|D9JYJ^^qq^\//\\\///^;ex;print
Re: Match string in array
by chester (Hermit) on Oct 03, 2005 at 19:15 UTC
    The easy way...

    use warnings; use strict; use Set::Array; my $array1 = Set::Array->new('one','red','orange','brown','green','blu +e','scarlett','fourteen'); my $array2 = Set::Array->new('red','orange','yellow','green','blue','i +ndigo','violet'); print "In array1, not in array2:\n"; print join "\n", $array1->difference($array2), "\n"; print "In array2, not in array1:\n"; print join "\n", $array2->difference($array1), "\n";

    Output:

    In array1, not in array2: fourteen one brown scarlett In array2, not in array1: violet indigo yellow
Re: Match string in array
by polypompholyx (Chaplain) on Oct 03, 2005 at 19:09 UTC

    You probably want something like this: use a hash to record all the items in the first array, then grep for items in the second array that you haven't already seen:

    my %seen_in_1; $seen_in_1{$_}++ for @rray1; my @in_2_but_not_1 = grep { not $seen_in_1{$_} } @rray2;

    Or, to avoid duplicates:

    my %seen_in_1; $seen_in_1{$_}++ for @rray1; my $seen_in_2_but_not_1; $seen_in_2_but_not_1{$_}++ for grep { not $seen_in_1{$_} } @rray2; my @in_2_but_not_1 = keys %seen_in_2_but_not_1;

Re: Match string in array
by gasho (Beadle) on Oct 03, 2005 at 19:09 UTC
    @FirstArray=qw(A B C D); @SecondArray=qw(D E F B); foreach $pr (@FirstArray){ #print "Property: $pr\n"; @match=(); @match=grep(/$pr/,@SecondArray); if (!@match){ push(@UniqueInFirstArrayNotFoundInSecondArray,$pr); } else { push(@FoundInBothArrays,$pr); } } print "".join("\n",@UniqueInFirstArrayNotFoundInSecondArray)."\n"; print "".join("\n",@FoundInBothArrays)."\n";

      Everytime you use grep, you are iterating through the list. Since you do that inside of loop, your algorithm is O(N*M). In contrast, JediWizard iterates once through a loop so his algorithm is linear. His approach is also conceptually simpler which results in cleaner code.

      -sauoq
      "My two cents aren't worth a dime.";
      
Re: Match string in array
by Hue-Bond (Priest) on Oct 04, 2005 at 20:28 UTC

    Here's my try:

    my @rray1=('one','red','orange','brown','green','blue','scarlett','fou +rteen'); my @rray2=('red','orange','yellow','green','blue','indigo','violet'); my @resul=grep { my $c=$_; grep /^$c$/, @rray1 } @rray2;

    This searches in @rray1 every element in @rray2. So, what you want is simply the inverse:

    my @resul=grep { my $c=$_; !grep /^$c$/, @rray1  } @rray2;

    --
    David Serrano