Ava Xue Ava Xue - 6 months ago 24
Perl Question

Perl: redundancy due to restart in foreach?

I was trying to grep string "Distance: " from "pairsAngles.txt" within each of over 2,000 subdirectories; the names of the subdirectories are obtained from a csv file. But for some reason foreach() restarts from the beginning every loop. So the output looks like this:
enter image description here
Apparently all the Distances are supposed to be in one column...

I'm not sure which step is causing the problem.
Code as follows:

#!/usr/bin/perl -w
use strict;
use warnings;
use File::Find;
use List::MoreUtils qw(uniq);
use Cwd qw(cwd);
use Text::CSV_XS;
use Data::Dumper;

my @pairs=qw();
my @result=();

my $in;
my $out;
my $pairs;
my $dist = "";
my $dir = "/home/avabelieve/aaPROJECT/helicalPair_ax/selectedPairs/renumberedPdb/clusterPairs-1.25-12-05_windows.12.resle3.2A.RMSD1.3/oligomerAngle";

my $cluster = "clst1.csv";
open ($in, $cluster) || die "cannot open \"$cluster\": $!";

my $cU = "clst1Updated.csv";
open ($out, ">$cU") || die "cannot open '$cU' $!";

my $csv = Text::CSV_XS->new ({ binary => 1, auto_diag => 1, eol => $/ });

while (my $c1 = <$in>) {
chomp $c1;
push @pairs, $c1;

foreach $c1 (uniq @pairs) {
find (\&Matches, "$dir/$c1");
sub Matches {
open ($pairs, "pairsAngles.txt") or die "$!";

while (my $dist = <$pairs>) {

if ($dist =~ m/Distance: /) {

chomp $dist;
push (@result, "$dist\n");
@result = split "\t", $dist;
}

}
}
}
chdir "..";

if (not $csv->eof) {
$csv->error_diag();
}
$csv->say ($out, [uniq @pairs, @result]);
}
close $out or die "$!";

Answer

The while loop adds to the list of @pairs.

while (my $c1 = <$in>) {    
    chomp $c1;
    push @pairs, $c1;

The foreach loop iterates over those pairs.

foreach $c1 (uniq @pairs) {
    find (\&Matches, "$dir/$c1");

Since the foreach loop is inside the while loop, every time a pair is added to @pairs the foreach loop will iterate over the ever growing @pairs all over again starting from the beginning.

To avoid this, finish building @pairs and then loop over it.

while (my $c1 = <$in>) {    
    chomp $c1;
    push @pairs, $c1;
}

foreach $c1 (uniq @pairs) {
    find (\&Matches, "$dir/$c1");
    ...
}

Incidentally, that while loop can be better written to take advantage of chomp working on a list.

my @pairs = <$in>;
chomp @pairs;
Comments