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

Dear all, I am trying to write a fairly simple script that takes a pathway, and writes out all the possible pairs and the 'steps' between the pairs, ie. 1 means that they are beside each other in the pathway and 2 means that there is another unit between them. However my output for the 'steps' is incorrect, the second time I go through everything is +1 (compare desired and current output). Any help is appreciated. thanks.

input

PA5098 PA5100 PA5092 PA3175

desired output

PA5098 PA5100 1 PA5098 PA5092 2 PA5098 PA3175 3 PA5100 PA5092 1 PA5100 PA3175 2 PA5092 PA3175 1

current output

PA5098 PA5100 1 PA5098 PA5092 2 PA5098 PA3175 3 PA5100 PA5092 2 PA5100 PA3175 3 PA5092 PA3175 3

code

############# open pathways output list with PA01 locus IDs my $in=$ARGV[1] || "pathways.col"; open (IN,$in) or die "cannot open $in\n"; ## my $out="$in.$org.stepSize.tab"; open(OUT,">",$out); # my %HoCplx2ID; my %HoPwyPair;my %HoPairs; while (my $lines=<IN>){ next if ($lines =~/^#/); next if ($lines =~/^UNIQUE-ID/); chomp $lines; my @cols=split(/\t/,$lines); my $cmplxID=$cols[0]; my $cmplxNm=$cols[1]; my @restCols=@cols[2..$#cols]; my @cycIDs=grep(/^GCXG-/, @restCols); @cycIDs=grep($_ ne '',@cycIDs); my $pwySize=scalar(@cycIDs); push (@{$HoCplx2ID{$cmplxID}},@cycIDs); } close(IN); ########### my %HoP; foreach my $pwy (keys %HoCplx2ID){ my @genes=@{$HoCplx2ID{$pwy}}; my $numbGenes=scalar(@genes); for (my $i=0;$i<$numbGenes;$i++){ for (my $j=1;$j<$numbGenes;$j++){ my $pair=join +("-",$HoCycID2Loc{$genes[$i]},$HoCycID2Loc{$genes[$j]}); my $rev_pair=join("-",$HoCycID2Loc{$genes[$j]} +,$HoCycID2Loc{$genes[$i]}); if (($genes[$i] ne $genes[$j]) && (!exists($Ho +P{$rev_pair}))){ print OUT join("\t",$HoCycID2Loc{$gene +s[$i]},$HoCycID2Loc{$genes[$i+1]},$j)."\n"; $HoP{$pair}=1; } } } }

Replies are listed 'Best First'.
Re: problem with loop
by McA (Priest) on Oct 27, 2014 at 11:50 UTC

    Hi,

    probably something like this:

    #!/usr/bin/perl use strict; use warnings; use 5.010; my @list = qw(PA5098 PA5100 PA5092 PA3175); for (my $i = 0; $i < @list - 1; $i++) { for (my $j = $i + 1; $j < @list; $j++) { my $diff = $j - $i; print "$list[$i] $list[$j] $diff\n"; } }

    Be aware: You need a special case when list has less than two elements.

    Regards
    McA

      You need a special case when list has less than two elements.

      No special case seems needed: inner loop just executes 0 times. (Update: Also works with 5.8.9.)

      thanks - simple
Re: problem with loop
by AnomalousMonk (Archbishop) on Oct 27, 2014 at 13:43 UTC

    Another way. No special-casing needed for 0, 1 element arrays/lists.

    c:\@Work\Perl>perl -wMstrict -le "my @node_names = qw(PA5098 PA5100 PA5092 PA3175); ;; for my $i (0 .. $#node_names) { my @following = $i+1 .. $#node_names; for my $j (@following) { print qq{$node_names[$i] $node_names[$j] }, $j - $i; } } " PA5098 PA5100 1 PA5098 PA5092 2 PA5098 PA3175 3 PA5100 PA5092 1 PA5100 PA3175 2 PA5092 PA3175 1

Re: problem with loop
by 2teez (Vicar) on Oct 27, 2014 at 14:51 UTC

    Or this:

    use warnings; use strict; my @p = qw[PA5098 PA5100 PA5092 PA3175]; for my $i ( 0 .. $#p ) { last if $i == $#p; for my $j ( 0 .. $#p ) { print join( " " => ( $p[$i], $p[$j], $j - $i ) ), $/ unless $i + >= $j; } }
    Output
    PA5098 PA5100 1 PA5098 PA5092 2 PA5098 PA3175 3 PA5100 PA5092 1 PA5100 PA3175 2 PA5092 PA3175 1
    I kind of like AnomalousMonk solution, because it has no help from ifs and unless. McA solution is also cool for me, but I don't like C-for loop in perl! :)

    If you tell me, I'll forget.
    If you show me, I'll remember.
    if you involve me, I'll understand.
    --- Author unknown to me