Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Deleting elements of one list using another

by Sj03rd (Initiate)
on Aug 02, 2012 at 08:00 UTC ( [id://984971]=perlquestion: print w/replies, xml ) Need Help??

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

Greetings to you, oh great Monks

I would like to compare two arrays and keep only those elements that PARTIALLY intersect. For example, let the two array's be:

@arr1 = ("0000007 | John | ABC.txt | 42","0000014 | Jane | XYZ.txt | 34","0000017 | Jessica | GHI.txt | 21", etc);
@arr2 = (0000007, 0000014);
This should result in a text file arr3.dat that contains something like
0000007 | John | ABC.txt | 42
0000014 | Jane | XYZ.txt | 34

I know I should use hashes and know how to split element-by-element but can't figure this one out.

EDIT: CODE ADDED, SORRY FOR BEING UNSPECIFIC. THE FINAL ROW SUGGESTS THAT THE HASHING GOES WRONG...
EDIT AGAIN: SOLUTION BY nemesdani WORKS FINE (BUT SEE MY REPLY).
Thanks!

use feature ':5.10'; open (KEYFILE, "arr2.txt"); @arr2 = <KEYFILE>; close(KEYFILE); # Declare and fill up the hash my %elements; foreach (@arr2) { $elements{$_} = 1; }; #I'm repeating this for several quarterly files: for($year=2006; $year<2012; $year=$year+1){ for($i=1; $i<5; $i=$i+1){ # Load each quarterly file $filea = $year . "QTR" . $i . "arr1.txt"; open(MYINFILE, $filea); @arr1 = <MYINFILE>; close(MYINFILE); $sizegn = @arr1; # For each entry in the quarterly file for($j=0; $j<$sizegn; $j++){ # Pick only lines that contain the string "txt" if($arr1[$j] =~ m/txt/){ # splits the elements of @arr1, and format the first e +lement into 7-digit number: @arraydata = split(/\|/, $arr1[$j]); my $element = sprintf("%07d", $arraydata[0]); # now check if $element is in hash : if (exists $elements{$element}){ open(MYOUTFILE, ">>Arr3.dat"); print MYOUTFILE $arr1[$j]; close(MYOUTFILE); } print "D'oh - '$element' not found\n" unless (exists $ +elements{$element}); } } } }

Replies are listed 'Best First'.
Re: Deleting elements of one list using another
by Anonymous Monk on Aug 02, 2012 at 08:11 UTC
Re: Deleting elements of one list using another
by nemesdani (Friar) on Aug 02, 2012 at 08:40 UTC
    Untested and unnecessary verbose, but I think you'll get the idea:

    use strict; use warnings; my @arr1 = ("John, ABC, 42","Jane, XYZ, 34","Jessica, GHI, 21"); my @arr2 = ("ABC", "XYZ"); my @arr3; my %seen; foreach my $arr1(@arr1) { my @splitted = split (/,/, $arr1); foreach my $arr2(@arr2) { if (grep(/$arr2/, @splitted)) { unless ($seen{$arr1} ){ push (@arr3, $arr1); } } } } for (@arr3) {print "$_\n";}

    I'm too lazy to be proud of being impatient.
      Great, this works fine for me. Flawless code except for  @splitted in the  grep command which should be  @splitted[0]. Thanks!
        You mean $splitted[0]? :)
        But no. splitted[0] contains "John" in the first loop, than "Jane", finally "Jessica". You'd like to grep the whole "John ABC 42" for ABC, don't you?
        Otherwise I haven't understand the problem well enough.

        I'm too lazy to be proud of being impatient.
Re: Deleting elements of one list using another
by jwkrahn (Abbot) on Aug 02, 2012 at 09:45 UTC
    $ perl -le' use Data::Dumper; my @arr1 = ( "John, ABC, 42", "Jane, XYZ, 34", "Jessica, GHI, 21" ); my @arr2 = ( "ABC", "XYZ" ); my $pattern = join "|", @arr2; my @arr3 = grep /$pattern/, @arr1; print Dumper \@arr3; ' $VAR1 = [ 'John, ABC, 42', 'Jane, XYZ, 34' ];
      Right idea but you aren't using anything to anchor the pattern, so you would also match 'JohnABC, CDE, 14'
      @arr1 = ("0000007 | John | ABC.txt | 42","0000014 | Jane | XYZ.txt | 3 +4","0000017 | Jessica | GHI.txt | 21", etc); @arr2 = ('0000007', '0000014'); my $re = join('|',@arr2); my @arr3 = grep /^(?:$re)\s/, @arr1; print join("\n",@arr3),"\n";

                      - Ant
                      - Some of my best work - (1 2 3)

Re: Deleting elements of one list using another
by aaron_baugher (Curate) on Aug 02, 2012 at 09:18 UTC

    In pseudo-code:

    make a hash of @arr2 instantiate @arr3 for each element of @arr1 split it to get the second field if that field is a key in the hash push the element onto @arr3

    Aaron B.
    Available for small or large Perl jobs; see my home node.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://984971]
Approved by Ratazong
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others learning in the Monastery: (7)
As of 2024-04-23 10:07 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found