-1

The desire here is to look at any rows with a common, sorted third row, and to give output based on this group of rows. (Note there are other properties of the table besides the common third row, but we won't look at them, now.) Before looking at the output, let's look at these groups of rows. If we have

Input:

0.016   0.032   1  
0.032   0.048   1  
0.048   0.064   1  
0.064   0.08    1  
0.08    0.096   1  
0.096   0.112   1  
0.112   0.128   0  
0.128   0.144   0  
0.144   0.16    0  
0.16    0.176   0  
0.176   0.192   0  
0.192   0.208   0  

That means we have two groups of rows:

one with a common third column value, 1

0.016   0.032   1  
0.032   0.048   1  
0.048   0.064   1  
0.064   0.08    1  
0.08    0.096   1  
0.096   0.112   1  

and a second with a common, 0 value.

0.112   0.128   0  
0.128   0.144   0  
0.144   0.16    0  
0.16    0.176   0  
0.176   0.192   0  
0.192   0.208   0

For each of these, we want to keep three values:

  1. the first column of the first row

  2. the second column of the last row

  3. the common, third-column value

That finally gives us

Desired output:

0.016 0.112 1  
0.112 0.208 0  
2
  • 6
    What have you tried? How did it fail? It's unclear how you would like to rearrange the file, please try to describe it in other words.
    – choroba
    Feb 28, 2019 at 6:07
  • It tried using awk and keeping the first column and the last. I think looking at input and the desired output makes it quite clear
    – aaa
    Feb 28, 2019 at 6:14

3 Answers 3

0

Perl to the rescue!

perl -ane '
    sub out { print "@_\n" }
    if ($F[2] != $three) {
        out($one, $two, $three) if defined $one;
        ($one, $three) = @F[0, 2];
    }
    $two = $F[1];
    END { out($one, $two, $three) }
    ' < input > output
  • -n reads the input line by line and runs the code for each line;
  • -a splits each line into the @F array on whitespace;
  • the if defined $one skips outputing the first line (it's third column is different to the previous one, but there's nothing to output yet);
  • the END block is needed to print the final block
0

I did it using awk:

awk 'BEGIN{f=0;OFS=" ";t=0;}  {if(f == 0 && $3 == 1) {ff=$1;f=1;next} if(f==1 && $3 == 1) {r=$2;} \
 if(t == 0 && $3 == 0) {print ff,r,1;ff=$1;t=1;next} if(t==1 && $3 == 0) {r=$2;}}  END{print ff,r,0}' file

It seems large but approach is simple, check if last column is 1 or 0, and then print 1st column of 1st line and 2nd column of last line.

Shorter Version:

awk 'BEGIN{f=0;OFS=" ";t=0;}  {if($3 == 1) {if(f==0){ff=$1;f=1;next} else{r=$2;}} \
else{if(t==0){print ff,r,1;ff=$1;t=1;next} else{r=$2;}}}  END{print ff,r,0}' file

Initially f and t has value 0, then for the first time $3==0 then ff will be equal to first column and f=1, and for further lines we will take r=$2. Similarly for $3==0.

0

You can do it with Perl with slurping the file and operating a regex over it:

$ perl -0777 -pe 's/^(\H+).*\h(\d+)\n(?:.*\h\2\n)*(?:.*\h(\H+)\h+\2$)/$1 $3 $2/mg' inp.file

Output:

0.016 0.112 1
0.112 0.208 0

Explanation:

  • Slurp the whole file into one record, $_, and then operate the regex over it.
  • The regex essentially looks for a block of text whose last fields match and then operates over it.
  • It looks at the block via 3 regex portions:
    • a) The first portion upto the first newline of the block.
    • b) The (optional) second portion, 0 or more lines, whose last field matches the first portion's.
    • c) The third portion, whose last field matches the last field of the first portion's. At the same time we record the 2nd field of the third portion.
    • d) Now we replace the entire block with the first field of the first portion, followed by the second field of the third portion, and the last field of the first portion.

Here's the same Perl code shown above, but sprinkled with self-contained comments and formatted for clarity:

$ perl -0777 -pe '
   s{
      ^(\H+).*\h(\d+)\n   (?#:the first row.)
      (?:.*\h\2\n)*       (?#:0 or more rows, whose last field matches the 1st row"s last.)
      (?:.*\h(\H+)\h+\2$) (?#:the  last  row, whose last field matches the 1st row"s last.)
   }{
      my($first_row_first_col, $last_row_second_col, $common_index) = ($1, $3, $2);
      join " ", $first_row_first_col, $last_row_second_col, $common_index;
   }gemx;
' inp.file

Not the answer you're looking for? Browse other questions tagged .