MacA
MacA

Reputation: 25

awk - calculations across lines of an ascii-file

I have an ascii-file with the following structure:

1,0,4,0,0,0,0,0,0,0,0
1,0,4,0,0,0,0,0,0,0,0
1,0,4,0,0,0,0,0,0,0,0
1,0,3,0,0,0,0.04,0,0,990,0
1,0,3,0,0,0,0.12,0,0,3760,0
1,0,3,0,0,0,0.21,0,0,5372,0
1,0,4,0,0,0,0,0,0,0,0
1,0,4,0,0,0,0,0,0,0,0
1,0,4,0,0,0,0,0,0,0,0
1,0,4,0,0,0,0,0,0,0,0
1,0,4,0,0,0,0,0,0,0,0
1,0,4,0,0,0,0,0,0,0,0
.
.
.

The zeros stand for "random" numbers I need not to take care of.

Where column 3 is equal to 3 (always a block of three) I have to perform some calculations with the columns 7 and 10:

I need to calculate (0.04*990)+(0.12*3760)+(0.21*5372) and insert the result in column 5 of all three lines. The values in column 10 will be different in the next "block of three".

Previously I have done a lot ascii-file editing with awk, so if possible I would like to use it here also.

My main problem is to access the next two lines after finding column 3 = 3 and then to continue searching two lines further.


The result should look like this:

1,0,4,0,0,0,0,0,0,0,0
1,0,4,0,0,0,0,0,0,0,0
1,0,4,0,0,0,0,0,0,0,0
1,0,3,0,1618.92,0,0.04,0,0,990,0
1,0,3,0,1618.92,0,0.12,0,0,3760,0
1,0,3,0,1618.92,0,0.21,0,0,5372,0
1,0,4,0,0,0,0,0,0,0,0
1,0,4,0,0,0,0,0,0,0,0
1,0,4,0,0,0,0,0,0,0,0
1,0,4,0,0,0,0,0,0,0,0
1,0,4,0,0,0,0,0,0,0,0
1,0,4,0,0,0,0,0,0,0,0
.
.
.

I hope that I was able to describe the problem, if not just ask and I will clarify!


I tried:

awk -F"," '$3 == "3"' in.dat > out.dat

and to combine it with

awk -v "n=line numer" -v "s=string to insert" '(NR==n) { print s } 1' input-file

but my main problem is that I did not know how to access the fields after the first line and to use it in a formula for calculation.

The formula I really need to use is way more complex, but I only posted here a simple example because it is no problem to adapt it to a more complex solution.

Upvotes: 2

Views: 99

Answers (2)

glenn jackman
glenn jackman

Reputation: 246807

awk's getline command serves you well here

awk -F, -v OFS=, '
    $3 == 3 {
        c = 0
        line1 = $0; c += $7 * $10; getline
        line2 = $0; c += $7 * $10; getline
        line3 = $0; c += $7 * $10
        $0 = line1; $5 = c; print
        $0 = line2; $5 = c; print
        $0 = line3; $5 = c
    }
    {print}
'

That's not DRY enough for my tastes, but it's only 3 lines and pretty readable.

DRY Solution

awk -F, -v OFS=, '
    $3 == 3 {
        c = 0
        for(i=1;i<=3;i++)
        {line[i] = $0; c += $7 * $10; getline}
        for(i=1;i<=3;i++)
        {$0 = line[i]; $5 = c; print}
        next
    }1
' 

Upvotes: 1

user3442743
user3442743

Reputation:

In awk

awk -F, '$3=="3"{a[++x]=$0;y+=($7*$10)}
         !x
         x==3{
            while(++i<=x){
                    split(a[i],b,",")
                    b[5]=y
                    for(j=1;j<length(b);j++)
                            c=j>1?c","b[j]:b[j]
                            print c
                            c=t
            }
            x=y=i=0
    }' file
  • If 3 is third field then Save line into array a and add the total to variable y
  • print if x is 0
  • If x is 3(i.e the third line)for the three lines in the array split them into another array
  • Change 5th element to y(total).
  • Recreate line in another loop.
  • Print line.

Shorter,less resource hungry way(credit to glenn jackmans answer for giving me the idea)

awk -F, '$3=="3"{a[++x]=$0;y+=($7*$10)}
         !x
         x==3{
            while(++i<=x){
                    $0=a[i]
                    $5=y
                    print
            }
            i=y=x=0
    }' test

Upvotes: 2

Related Questions