http://www.perlmonks.org?node_id=980782

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

Hi, I've been looking for a way to compare the current line in a loop to the previous line in the loop. I've been looking all day and can't seem to find an answer.

What I have so far:

my $previous = ''; while (<>) { @gtf = split /\s+/, $_; chomp(); if ("$gtf[9]" ne "$previous") { $gtf[2] =~ tr/ex*/ex1/; } else { $gtf[2]++; } }

Basically, I want to compare item 9 of @gtf in the current iteration with item 9 of @gtf from the last iteration and if they are different, restart the ex counter at 1. $gtf[2] is "ex1" and increases by 1 every iteration. Thanks!

Replies are listed 'Best First'.
Re: Comparing adjacent lines
by aaron_baugher (Curate) on Jul 10, 2012 at 02:08 UTC

    What do you want to happen to the data after you've made these changes? Print it out to a file? Save it to a database? Push it onto an array created outside the loop? As it stands, you make changes to the @gtf array, and then it's clobbered when the loop restarts and splits the next line into it. Since you haven't localized it to the loop, the last line will remain in it after the loop exits, but I doubt that's what you want.

    I'll go through your code and add some comments below, followed by my suggestions:

    my $previous = ''; while (<>) { @gtf = split /\s+/, $_; chomp(); # switch those two to chomp the line before you split it, # otherwise your chomp is meaningless. Also, those are # the default arguments to split: while(<>){ chomp; my @gtf = split; if ("$gtf[9]" ne "$previous") { # don't put quotes around single variables; potentially buggy if( $gtf[9] ne $previous ){ $gtf[2] =~ tr/ex*/ex1/; # this probably doesn't do what you want. # tr/// transliterates characters: here e becomes e, # x becomes x, and a literal asterisk becomes 1. # If you want to reset $gtf[2] back to 'ex1', just do so: $gtf[2] = 'ex1'; } else { $gtf[2]++; # this may bite you too. $x='ex9'; $x++; $x=='ey0' # you probably want to increment just the number: $gtf[2] =~ s/(\d+)/$1+1/e; } # now save $gtf[9] in $previous so it can be compared to the next li +ne $previous = $gtf[9]; # here is where you would print out the array values, or do whatever + you like with them }

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

      As you could probably tell, I'm new to Perl, so thanks for being gentle :) Thanks for the comments, they were extremely helpful. After the loop I am creating a new file; this program is for changing file formats.

      One thing though: after ex# has been replaced with ex1, the subsequent ex# with matching @gtf[9] don't count up from ex1. They revert to the original ex# value+1 and count from there. I think that rather than taking the new ex1, its using the default ex# (like you said, changes made to @gtf are clobbered when the loop restarts). I guess I could specify ex1 as its own variable before the loop, like The Code Captain suggested...I'll test and see what happens.

        I've been trying out different things and just can't get it to work...any ideas?

Re: Comparing adjacent lines
by The Code Captain (Initiate) on Jul 09, 2012 at 23:56 UTC

    Hi There

    I can see a few problems straight off. You compare to $previous but you never set $previous to anything except the empty string at the start. Probably not what you intended. Also you chomp() your input after you have tokenised it. Also probably not what you intended.

    I would suggest something like this (untested):

    my $previous=undef; my $ex=1; while(<>) { chomp(); @gtf=split(/\s+/, $_); if( ($#gtf>=9) && defined($previous) && ($gtf[9] eq $previous) ) { $ex+=1; } else { $ex=1; } $previous=($#gtf>=9)?$gtf[9]:undef; $gtf[2]="ex".$ex; }

    You don't have to check the size of your input ($#gtf) if you're not concerned with it, but remember that perl's autovivification will create elements of an array for you which may not be want you want so I prefer to check the element is there before accessing it.

Re: Comparing adjacent lines
by frozenwithjoy (Priest) on Jul 09, 2012 at 23:53 UTC
    Think about how you might do this in real life. Imagine picking something up with one hand, you take a good look at it, put it into your other hand and pick up the next object, take a good look at it and compare the two objects. Then you drop the oldest object, move the remaining object to the other hand and pick up a new object to compare... and so on. Basically, you need two hands.
Re: Comparing adjacent lines
by sundialsvc4 (Abbot) on Jul 10, 2012 at 03:50 UTC

    Okay, this one’s easy.   You simply need another variable, which will be used to contain the contents of the previous line seen.   You store the value of the current record (e.g. $_) into this variable at the end of the while-loop.

    During the first iteration through the loop, the value of this variable will be “undefined,” i.e. undef, which you can test for using the function, defined().   During this iteration, there will be no “previous line” to compare to, so you omit that part.