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

Hi

can somebody give me some pointers as to how I do the following

I have a piece of code that consists of two loops

while(<FILE1>) { chomp; my @fields = split(/:/, $_); my $result = qx{ /opt/bin/target -e$fields[2] }; print FILE2 "$fields[0]:$fields[1]:$result:NONBKID\n"; foreach my $configParameter (keys %{$configHash}) { my $nbkid = $configHash->{$configParameter}{'nbkid'}; my $ntid = $configHash->{$configParameter}{'ntid'}; if ($ntid eq $fields[1]) { print FILE2 "$fields[0]:$fields[1]:$result:$nbkid\n"; } } }
This produces an output file
ANY:spicejam:07F7817D470004327B471FC5327B050F:nbkufdc ANY:spicejam:07F7817D470004327B471FC5327B050F:NONBKID ANY:henders:07F7817D470004327B:nbhoijk ANY:henders:07F7817D470004327B:NONBKID ANY:riffty:07F7817D470:nbaz94k ANY:riffty:07F7817D470:NONBKID ANY:johbe:07F7817D470004327B471FC5327B050FE04379:n3456hk ANY:johbe:07F7817D470004327B471FC5327B050FE04379:NONBKID .... etc
What I wanted it to do was to either print the line with NONBKID in it or the line that matched the string compare but not both. e.g. The output should be
ANY:spicejam:07F7817D470004327B471FC5327B050F:NONBKID ANY:henders:07F7817D470004327B:nbhoijk ANY:riffty:07F7817D470:nbaz94k ANY:johbe:07F7817D470004327B471FC5327B050FE04379:NONBKID .... etc
I'm not sure how to achieve this. The outside loop iterates through each record and then the inside loop also iterates through potentially hundreds of records looking for a match with the outside loop record. So I need a match in the inside loop to overwite the print from the outside loop if a match exists.

Any help would be appreciated

Replies are listed 'Best First'.
Re: One loop or two
by locked_user sundialsvc4 (Abbot) on Aug 01, 2012 at 13:40 UTC

    If your script works well enough as it is, performance-wise, a solution might be quite simple ...

    1. Outside of the loop, declare:
      my $matchingbkid;.
    2. Where you now have print FILE2 ... NONBKID, replace with:
      $matchingbkid = "NONBKID"; # DEFAULT ASSUMPTION .
    3. In the inner loop, when you find the match, write:
      if ($ntid eq $fields[1]) { $matchingbkid = $bkid; last; # END THE LOOP - WE FOUND IT }
    4. Now, after the end of the inner loop:
      print FILE2 "$fields[0]:$fields1:$result:$matchingbkid\n";

    The double-loop strategy in this example is retained ... if it works fast enough for your purposes there is no need to redesign it.   The difference is that the inner loop starts with the assumption that the key will be NONBKID, then sets about to try to prove otherwise.   When the first matching key is discovered, it captures the key then quits looking further.   A single output record is generated for either case.

    The # COMMENTS are merely for clarity.

      Excellent. A simple solution staring me in the face. Thank you very much
Re: One loop or two
by jayto (Acolyte) on Aug 01, 2012 at 13:40 UTC

    What string are you comparing? nbkid?? What does your input look like??

    while(<FILE1>) { chomp; my @fields = split(/:/, $_); my $result = qx{ /opt/bin/target -e$fields[2] }; print FILE2 "$fields[0]:$fields[1]:$result:NONBKID\n"; foreach my $configParameter (keys %{$configHash}) { my $nbkid = $configHash->{$configParameter}{'nbkid'}; my $ntid = $configHash->{$configParameter}{'ntid'}; if ($ntid eq $fields[1]) { print FILE2 "$fields[0]:$fields[1]:$result:$nbkid\n"; } } }
    change to
    while(<FILE1>) { chomp; my @fields = split(/:/, $_); my $result = qx{ /opt/bin/target -e$fields[2] }; foreach my $configParameter (keys %{$configHash}) { my $nbkid = $configHash->{$configParameter}{'nbkid'}; my $ntid = $configHash->{$configParameter}{'ntid'}; if ($ntid eq $fields[1]) { print FILE2 "$fields[0]:$fields[1]:$result:$nbkid\n" i +f $field[3] eq $nbkid; print FILE2 "$fields[0]:$fields[1]:$result:NONBKID\n" if $fiel +d[3] ne $nbkid; } } }

    maybe this is what you want? some of your information wasn't clear to me

Re: One loop or two
by BillKSmith (Monsignor) on Aug 01, 2012 at 15:54 UTC

    One call to a module (You could use grep, but the module is more explicit) can replace the inner loop. Use of values rather than keys simplifies the syntax. The single print statement emphasizes your intent to print one line.

    use strict; use warnings; use List::MoreUtils qw( first_value ); my %configHash; while(<FILE1>) { chomp; my @fields = split(/:/, $_); my $result = qx{ /opt/bin/target -e$fields[2] }; my $id = first_value {$_->{'ntid'} eq $fields[1]} values %configHash; my $source = $id ? $id->{nbkid} : 'NONBKID'; print FILE2 "$fields[0]:$fields[1]:$result:$source\n"; }

    untested