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

Hi Perl Monkers, I wrote a stupid code (see below) to combine two files and it obviously is wrong. I am not very familiar with Perl Join or grep and can't seem to figure out the code from scratch using these functions. ANy help perl monkers?

1st file: pizza pickle omellete coke blackforest croissant 2nd file: salt pizza 1 salt pickle 1 pepper omelette 1 pepper pickle 1 I want is: (If ingredient in file 2 is not found in food from file 1, +annotate it as "0" instead of "1"). salt pizza 1 salt pickle 1 salt omellette 1 salt coke 0 salt blackforest 0 salt croissant 0 sugar pizza 0 sugar pickle 0 sugar omellette 0 sugar coke 1 sugar blackforest 1 sugar croissant 0 I wrote this which is obviously wrong: open(INPUTR,"<$1file") || die "Can't open \$1file for reading.\n"; while($line=<INPUTR>){     chomp $line;     $food = $line;         open(INPUTR1,"<$2file") || die "Can't open \$2file for reading +.\n";         while($line1=<INPUTR1>){             chomp $line1;             @toks = split(/\t/, $line1);             $ingredient = uc$toks[0];             $food1 = uc$toks[1];             $linemod = $line1;             if ($food1 !~ $food){                 $linemod = $ingredient."\t".$food."\t"."0";             }         }         close(INPUTR1);         print OUTD $linemod."\n"; }

Replies are listed 'Best First'.
Re: Is it Perl "join" that can help me?
by choroba (Cardinal) on May 13, 2012 at 07:31 UTC
    What are you trying to achieve? Why is there 1 for salt omellette, if there is no salt omellette in the 2nd file? (Also, you have omellete with single t in the 1st file).
Re: Is it Perl "join" that can help me?
by davido (Cardinal) on May 13, 2012 at 07:56 UTC

    I'm lost. Why is "pepper" not found in your desired output, and how does "sugar" find its way into your desired output when it's not part of your input files?


    Dave

Re: Is it Perl "join" that can help me?
by tobyink (Canon) on May 13, 2012 at 08:47 UTC
    use 5.010; use strict; use File::Temp (); use Path::Class (); my $temp = Path::Class::Dir->new( File::Temp::tempdir() ); my $file1 = $temp->file('file1.txt'); my $file2 = $temp->file('file2.txt'); # Create files to operate on. # You already have these files, so you don't need to make them. print { $file1->openw } <<DATA; pizza pickle omellete coke blackforest croissant DATA # (note: following includes tabs - beware if # copying and pasting from PerlMonks!) print { $file2->openw } <<DATA; salt pizza 1 salt pickle 1 pepper omelette 1 pepper pickle 1 sugar coke 1 DATA # OK, now let's start the real work... # List of all meals my @meals = $file1->slurp(chomp => 1); # This will help us generate a list of all ingredients. my %ingredients; # Record pairings between ingredients and meals my %pairings; # Loop through file2 building up previous hashes. for ($file2->slurp(chomp => 1)) { my ($ing, $meal, $bool) = split /\t/; $ingredients{$ing} = 1; # record that the ingredient exist +s at all $pairings{$ing, $meal} = $bool; # record the pairing of ingredient + and meal } # List of all ingredients my @ingredients = keys %ingredients; # For each pair of ingredient and meal... for my $i (sort @ingredients) { for my $m (sort @meals) { printf( "%s\t%s\t%d\n", # format string $i, # ingredient $m, # meal $pairings{$i, $m}, # paired? ); # Note that $pairings{$i, $m} is # converted to an integer by printf # because of the '%d' formatting # code. Thus if there's no pairing, # we get '0'. } } # Clean up temp dir $temp->rmtree;

    An alternative way of writing the output loop would be to use List::MapMulti, in which case it would be:

    my $pairs = iterator_multi(\@ingredients, \@meals); while (my ($i, $m) = $pairs->()) { printf("%s\t%s\t%d\n", $i, $m, !!$pairings{$i, $m}); }

    Or even:

    say for mapm { join "\t", @_, 0+ $pairings{$_[0], $_[1]} } \@ingredien +ts, \@meals;
    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
Re: Is it Perl "join" that can help me?
by AnomalousMonk (Archbishop) on May 13, 2012 at 23:29 UTC

    One more point about the OPed code: variable names like  $1file and  $2file are tres illegal: a user-code defined variable name must begin with an alpha. (Perl defines special variables like  $1 $@ $^W etc., but we all know that Perl is special!) (Actually, I believe there is a way around the alpha-first-character rule for user code, but that's another story.)