Take each number in table row and find the difference from the corresponding line

I have a two files containing numbers like below. First one contains one number on each line, the other is a table of numbers, each separated by a space. There are the same number of lines in each file.

I want to take each number in the row of the table and find the difference from the corresponding line of the first list. So each value in the row is subtracted from the value in the list at the corresponding line number using awk.

For example

5
6
7
8
9
1 2 3 4 5
5 4 3 2 1
1 2 3 4 5
1 2 3 4 5
5 4 3 2 1

Result should be

-4 -3 -2 -1 0
-1 -2 -3 -4 -5
-6 -5 -4 -3 -2
-7 -6 -5 -4 -3
-4 -5 -6 -7 -8 

Actual files will be something like below

0.4117983
0.4735530
0.6167929
0.7095670
0.7897300
0.8662801
0.9425200
1.020120
1.099846
1.181320
1.263659
1.347084
1.431774
1.520824
1.610451
1.701591
1.793289
1.882924
1.969465
0.403564 0.403564 0.403564 0.403564 0.403564
0.464079 0.464079 0.464079 0.464079 0.464079
0.604454 0.604454 0.604454 0.604454 0.604454
0.695379 0.695379 0.695379 0.695379 0.695379
0.773935 0.773935 0.773935 0.773935 0.773935
0.848954 0.848954 0.848954 0.848954 0.848954
0.923670 0.923670 0.923670 0.923670 0.923670
0.999718 0.999718 0.999718 0.999718 0.999718
1.077850 1.077850 1.077850 1.077850 1.077850
1.157690 1.157690 1.157690 1.157690 1.157690
1.238390 1.238390 1.238390 1.238390 1.238390
1.320140 1.320140 1.320140 1.320140 1.320140
1.403130 1.403130 1.403130 1.403130 1.403130
1.520820 1.520820 1.520820 1.520820 1.520820
1.642660 1.642660 1.642660 1.642660 1.642660
1.735620 1.735620 1.735620 1.735620 1.735620
1.829160 1.829160 1.829160 1.829160 1.829160
1.920580 1.920580 1.920580 1.920580 1.920580
2.008860 2.008860 2.008860 2.008860 2.008860

It works great. Thanks buddy. :stuck_out_tongue:

awk only :wink:

awk 'NR==FNR{a[NR]=$0;next}{for(i=0;++i<=NF;){$i=($i-a[FNR])}}1'  file1 file2

It works ok, but there is a feature I never encountered before. What's the purpose of the 1 at the end. Without it does not work when I redirect the output to a file. So it must be quite important!!!

1 means true equivalent to { print }

Oh. Ok, I get it!!!

Hello ,
perhaps you would want a little faster with larger data sets. use the Swiss Knife. :wink:

gaurav@localhost:~$ cat file1 
5
6
7
8
9
gaurav@localhost:~$ cat file2 
1 2 3 4 5
5 4 3 2 1
1 2 3 4 5
1 2 3 4 5
5 4 3 2 1
gaurav@localhost:~$ perl -e 'open(F1,"<file1");open(F2,"<file2");while(($l1=<F1>)&&($l2=<F2>)) {foreach (split(/\s+/,$l2)){ print $_ - $l1," ";}print "\n"}close(F1);close(F2);'
-4 -3 -2 -1 0 
-1 -2 -3 -4 -5 
-6 -5 -4 -3 -2 
-7 -6 -5 -4 -3 
-4 -5 -6 -7 -8 
gaurav@localhost:~$ 

Regards.
Gaurav.

Brilliant!!! :smiley:

Also suitable for large files:

awk '{getline x<f; for(i=1;i<=NF;i++)$i=$i-x}1' f=file1 file2

The command gives a good sample on how to use NR and FNR.:b:

Yep, but Scrutinizer solution is the best for large files :b:

I am trying to put a perl command in a csh script, but having problems. Output is empty.

Must be some problem when I try to pass the filenames perhaps.

    set file1 = $fin1.vtab
    set file2 = $fin2.vtab
    perl -e ' open(F1,"<$file1"); open(F2,"<$file2");    \
      while( ($l1=<F1>) && ($l2=<F2>) ) {                    \
        foreach (split(/\s+/,$l2)) { print $_ - $l1," "; }    \
        print "\n"                                                                          \
      }                                                                                           \
      close(F1); close(F2); ' > $fin1-$fin2.vtab