Transforming data by a constant - awk

I have a file like this
3 4 5 6 7 1
4 5 4 4 4 4
2 2 3 3 2 1
and I want to multiple every data point by a constant (e.g. 10) to get the following output
30 40 50 60 70 10
40 50 40 40 40 40
20 20 30 30 20 10
I have been trying to do it like this without success
awk '{i=1; while (i<=NF) print $i*10; i++}'

You are using a while loop, whereas a simple for would suffice:
$ awk '{for (i=1; i<=NF; i++) $i*=10}1' file
30 40 50 60 70 10
40 50 40 40 40 40
20 20 30 30 20 10
A while needs a finish condition and you are not providing none. Also, if the amount of loops to do is a fixed number, it is better to just use for.
Note that you were saying print, so that every field would be printed in a different line. By replacing each one of them and using 1 to print it afterwards, you keep the format.

Related

Retrieve value from different fields for each record of an Access table

I would be more than appreciative for some help here, as I have been having some serious problems with this.
Background:
I have a list of unique records. For each record I have a monotonically increasing pattern (either A, B or C), and a development position (1 to 5) assigned to it.
So each of the 3 patterns is set out in five fields representing the development period.
Problem:
I need to retrieve the percentages relating to the relevant development periods, from different fields for each row. It should be in a single column called "Output".
Example:
Apologies, not sure how to attach a table here, but the fields are below, the table is a transpose of these fields.
ID - (1,2,3,4,5)
Pattern - (A, B, C, A, C)
Dev - (1,5,3,4,2)
1 - (20%, 15%, 25%, 20%, 25%)
2 - (40%, 35%, 40%, 40%, 40%)
3 - (60%, 65%, 60%, 60%, 60%)
4 - (80%, 85%, 65%, 80%, 65%)
5 - (100%, 100%, 100%, 100%, 100%)
Output - (20%, 100%, 60%, 80%, 40%)
In MS Excel, I could simply use a HLOOKUP or OFFSET function to do this. But how do I do this in Access? The best I have come up with so far is Output: Eval([Category]) but this doesn't seem to achieve what I want which is to select the "Dev" field, and treat this as a field when building an expression.
In practice, I have more than 100 development periods to play with, and over 800 different patterns, so "switch" methods can't work here I think.
Thanks in advance,
alch84
Assuming that
[ID] is a unique column (primary key), and
the source column for [Output] only depends on the value of [Dev]
then this seems to work:
UPDATE tblAlvo SET Output = DLOOKUP("[" & Dev & "]", "tblAlvo", "ID=" & ID)
Before:
ID Pattern Dev 1 2 3 4 5 Output
-- ------- --- -- -- -- -- --- ------
1 A 1 20 40 60 80 100
2 B 5 15 35 65 85 100
3 C 3 25 40 60 65 100
4 A 4 20 40 60 80 100
5 C 2 25 40 60 65 100
After:
ID Pattern Dev 1 2 3 4 5 Output
-- ------- --- -- -- -- -- --- ------
1 A 1 20 40 60 80 100 20
2 B 5 15 35 65 85 100 100
3 C 3 25 40 60 65 100 60
4 A 4 20 40 60 80 100 80
5 C 2 25 40 60 65 100 40

Replace characters with awk

I have the following file:
61 12451
61 13451
61 14451
61 15415
12 48469
12 78456
12 47845
32 45778
32 48745
32 47845
32 52448
32 87451
The output I want is the following, for example, 61 s are replaced by 1 as they are the first occurrence and they are repeated 4 times, then the second column goes from 2 to 5, as these are pairwise comparisons, 1 to 1 is ignored, but the second column should start from 2, so on for the rest.
1 2
1 3
1 4
1 5
2 3
2 4
2 5
3 4
3 5
3 6
3 7
3 8
Any suggestion on how to achieve this with AWK? Thanks!
It could be written in one awk command like this
awk '{a[NR]=$1;b[NR]=$2;c[NR]=$1;d[NR]=$2} END {for(i=1; i<=NR; i++){if(i==1){c[i]=1;d[i]=2}else if(a[i]==a[i-1]){c[i]=c[i-1];d[i]=1+d[i-1]}else{c[i]=1+c[i-1];d[i]=c[i]+1}print c[i],d[i]}}' pairwise.txt > output.txt
Here a and b are the arrays that read the first and second column of the file. The new values are stored in arrays c and d as first & second column and are printed to the output file.
not sure if this one-liner helps:
awk '$1!=p{++i;j=i+1}{print i,j++;p=$1}' file
at least it gives the desired output.

Excluding rows dynamically

Let's assume we have the following:
A
1 10
2 20
3 30
4 20
5 10
6 30
7 20
8
9
10 =(AVERAGE(A1:A7)
11 4
12 6
I would like to be able to find a way to calculate the Average of A1-A7 into cell A10 while excluding row range defined in A11 and A12. That is, according to the above setup the result should be 20:
((10 + 20 + 30 + 20) / 4) = 20
because if rows 4,5 and 6 are excluded what's left is rows 1,2,3,7 to be averaged.
Two other options:
=AVERAGE(FILTER(A1:A7,ISNA(MATCH(ROW(A1:A7),A11:A12,0))))
=ArrayFormula(AVERAGEIF(MATCH(ROW(A1:A7),A11:A12,0),NA(),A1:A7))
Seems to meet your requirement, though not flexible:
=(sum(A1:A7)-indirect("A"&A11)-indirect("A"&A12))/(count(A1:A7)-2)
Adjust re misunderstanding of requirements:
=(SUM(A1:A7)-SUM(INDIRECT("A"&A11&":A"&A12)))/(COUNT(A1:A7)-A12+A11-1)

AWK reading a file and operate between different columns

I have three files!
coord.xvg
veloc.xvg
force.xvg
each of these files have lines with multiple numbers lets say 10000
I would like to construct a script that
opens the three files
reads columns
and make arithmetic operations between them for every line.
For example
if every file has 4 words
coord.xvg >> Time x y z
veloc.xvg >> Time vx vy vz
force.xvg >> Time fx fy fz
and c,v,f stands for coord.xvg, veloc.xvg,force.xvg
if I write the operation 2*v*v+c*f*c the output should be
column1 Column2 Column3 Column4
Time 2*vx*vx+cx*fx*cx 2*vy*vy+cy*fy*cy 2*vz*vz+cz*fz*cz
I have found in the internet the following
awk '{
{ getline < "coord.xvg" ; if (FNR==90307) for(i=1;i<=2;i+=1) c=$i}
{ getline < "veloc.xvg" ; if (FNR==90307) for(i=1;i<=2;i+=1) v=$i}
{ getline < "force.xvg" ; if (FNR==90307) for(i=1;i<=2;i+=1) f=$i}
}
END {print c+v+f}' coord.xvg
which stands for my files which I want to begin reading after 90307 lines.
but it didn't help me much as it returns only the last values of every variable
Any thought??
Something to get you started if I understood you correctly
$ cat *.xvg
Time 1 2 3
Time 4 5 6
Time 7 8 9
Time 10 11 12
Time 13 14 15
Time 16 17 18
Time 19 20 21
Time 22 23 24
Time 25 26 27
The following awk-script
{ if (FNR>=1) {
{ getline < "coord.xvg" ; c1=$2;c2=$3;c3=$4}
{ getline < "veloc.xvg" ; v1=$2;v2=$3;v3=$4}
{ getline < "force.xvg" ; f1=$2;f2=$3;f3=$4}
print c1,c2,c3,v1,v2,v3,f1,f2,f3
print $1, c1+v1+f1, c2+v2+f2, c3+v3+f3
}}
reads a line from each of the files and puts the data in variables
as can be seen here
$ awk -f s.awk coord.xvg
1 2 3 19 20 21 10 11 12
Time 30 33 36
4 5 6 22 23 24 13 14 15
Time 39 42 45
7 8 9 25 26 27 16 17 18
Time 48 51 54
The if (FNR>=1) part controls which lines are displayed. Counting starts at 1, change this to match your need. The actual calculations I leave to you :-)

How to sum up every 10 lines and calculate average using AWK?

I have a file containing N*10 lines, each line consisting of a number. I need to sum up every 10 lines and then print out an average for every such group. I know it's doable in awk, I just don't know how.
Try something like this:
$ cat input
1
2
3
4
5
6
2.5
3.5
4
$ awk '{sum+=$1} (NR%3)==0{print sum/3; sum=0;}' input
2
5
3.33333
(Adapt for 10-line blocks, obviously.)
May be something like this -
[jaypal:~/Temp] seq 20 > test.file
[jaypal:~/Temp] awk '
{sum+=$1}
(NR%10==0){avg=sum/10;print $1"\nTotal: "sum "\tAverage: "avg;sum=0;next}1' test.file
1
2
3
4
5
6
7
8
9
10
Total: 55 Average: 5.5
11
12
13
14
15
16
17
18
19
20
Total: 155 Average: 15.5
If you don't want all lines to be printed then the following would work.
[jaypal:~/Temp] awk '
{sum+=$1}
(NR%10==0){avg=sum/10;print "Total: "sum "\tAverage: "avg;sum=0;next}' test.file
Total: 55 Average: 5.5
Total: 155 Average: 15.5