2

Sample Input

file name
0.00   -1.0000   number1
0.00   -0.8000   number2
0.00   -0.6000   number3
0.00   -0.4000   number4
0.00   -0.2000   number5
0.00   0.0000   number6
0.00   0.2000   number7
0.00   0.4000   number8
0.00   0.6000   number9
0.00   0.8000   number10
0.00   1.0000   number11

0.02   -1.0000   number12
0.02   -0.8000   number13
0.02   -0.6000   number14
0.02   -0.4000   number15
0.02   -0.2000   number16
0.02   0.0000   number17
0.02   0.2000   number18
0.02   0.4000   number19
0.02   0.6000   number20
0.02   0.8000   number21
0.02   1.0000   number22

0.04   -1.0000   number23
0.04   -0.8000   number24
0.04   -0.6000   number25
0.04   -0.4000   number26
0.04   -0.2000   number27
0.04   0.0000   number28
0.04   0.2000   number29
0.04   0.4000   number30
0.04   0.6000   number31
0.04   0.8000   number32
0.04   1.0000   number33

goal

(Referring to columns/fields in awk nomenclature, ie. $1 = field 1)

As you can see, there are 3 blocks of data above. Within each block, $1 equals a constant value. For each block of $1 = constant, I would like to exchange $3 symmetrically around where $2 = 0. The result would be the following desired output:

desired output

file name
0.00   -1.0000   number11
0.00   -0.8000   number10
0.00   -0.6000   number9
0.00   -0.4000   number8
0.00   -0.2000   number7
0.00   0.0000   number6
0.00   0.2000   number5
0.00   0.4000   number4
0.00   0.6000   number3
0.00   0.8000   number2
0.00   1.0000   number1

0.02   -1.0000   number22
0.02   -0.8000   number21
0.02   -0.6000   number20
0.02   -0.4000   number19
0.02   -0.2000   number18
0.02   0.0000   number17
0.02   0.2000   number16
0.02   0.4000   number15
0.02   0.6000   number14
0.02   0.8000   number13
0.02   1.0000   number12

0.04   -1.0000   number33
0.04   -0.8000   number32
0.04   -0.6000   number31
0.04   -0.4000   number30
0.04   -0.2000   number29
0.04   0.0000   number28
0.04   0.2000   number27
0.04   0.4000   number26
0.04   0.6000   number25
0.04   0.8000   number24
0.04   1.0000   number23

background context

In my actual input, $1 continues in the sequence of {0.00..0.02..15.0}. Furthermore, within each block, $2 proceeds as {-14..0.2..14}. Therefore, in total there are 751 blocks, and each block alone consists of 141 lines (or 142 lines, including the additional title/empty line preceding each block).

So it would be helpful to have a script that can go through each of the 751 blocks one-by-one, and reflect that block's $3 arbitrary values symmetrically around the median line for that individual block (the 71st line in each block, or 72nd including the empty line above each block).

Thank you!

1

You tagged this with , but mentioned awk, so I hope it's okay to use that:

$ awk -vn=0 'NR == 1 {print; next}
             $0 != "" { k = $1; a[n] = $2; b[n] = $3; n++ } 
             $0 == "" { for (i = 0; i < n ; i++) { 
                           printf "%s   %s   %s\n", k, a[i], b[n-i-1]; } 
                        n=0; print   }' < data

On the very first line (NR == 1), we just print it and go on.

Then, for nonempty lines, it loads the second and third fields to arrays a and b, and for empty lines, it goes through the arrays and prints a in order, and b in the inverse order and finally resets the counter n.

This assumes that (1) the point to mirror over is actually in the middle; (2) the first field is always the same within each block (as it is in your code); and (3) that there is an empty line after each block (though additional empty lines shouldn't matter. Add an empty line at the very end if you don't have one there).

  • I just reviewed the first 2 blocks and the last block, and it seems to work for all of them except the first block. I guess this is because it begins with a title. Is there a good way around this? I like awk, but this code is currently beyond my ability to fine-tune. Otherwise, thank you very much for this! I might just delete the title and re-add it if necessary, so having this code to solve the rest is already great. – Blaise Mar 13 '19 at 17:12
  • To clarify, $3 is shifted up by one line in the first block. – Blaise Mar 13 '19 at 17:13
  • @Blaise, ah right, the title line. If it's just the very first line, it's easy to deal with, see edit. – ilkkachu Mar 13 '19 at 17:15
  • Seems to work perfectly now. I appreciate the explanation as well. Don't know how you guys can manipulate awk so thoroughly, but thank you very much! – Blaise Mar 13 '19 at 17:25
  • 1
    @ctac_, ah, yes, you could do without explicit comparison (except that ! $0 would match lines with just a single zero, while $0 == "" doesn't). But it's also clearer with the explicit comparison. As for the final block, you could of course put the "empty line" case in a function and also call it from END, but that would also have made the code a bit more complex. (I tried to keep it short enough so it doesn't look too horrible for a single command line.) – ilkkachu Mar 13 '19 at 18:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.