Kay
Kay

Reputation: 2077

Insert a row and a column in a matrix using awk

I have a gridded dataset with 250 rows x 300 columns in matrix form:

ifile.txt

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

I would like to insert the latitude values at the first column and longitude values at the top. Which looks like:

ofile.txt

         20.00 20.33 20.66 20.99 21.32 21.65 
 100.00      2     3     4     1     2     3
 100.33      3     4     5     2     4     6
 100.66      2     4     0     5     0     7
 100.99      0     0     5     6     3     8

The increment is 0.33

I can do it for a small size matrix in manually, but I can't able to get any idea how to get my output in my desired format. I was writing a script in the following way, but completely useless.

echo 20 > latitude.txt
for i in `seq 1 250`;do
i1=$(( i + 0.33 ))     #bash can't recognize fractions
echo $i1 >> latitude.txt
done

echo 100 > longitude.txt
for j in `seq 1 300`;do
j1=$(( j + 0.33 ))
echo $j1 >> longitude.txt
done

paste longitude.txt ifile.txt > dummy_file.txt
cat latitude.txt dummy_file.txt > ofile.txt

Upvotes: 1

Views: 829

Answers (4)

Ed Morton
Ed Morton

Reputation: 203665

$ cat tst.awk
BEGIN {
    lat = 100
    lon =  20
    latWid = lonWid = 6
    latDel = lonDel = 0.33
    latFmt = lonFmt = "%*.2f"
}
NR==1 {
    printf "%*s", latWid, ""
    for (i=1; i<=NF; i++) {
        printf lonFmt, lonWid, lon
        lon += lonDel
    }
    print ""
}
{
    printf latFmt, latWid, lat
    lat += latDel
    for (i=1; i<=NF; i++) {
        printf "%*s", lonWid, $i
    }
    print ""
}

$ awk -f tst.awk file
       20.00 20.33 20.66 20.99 21.32 21.65
100.00     2     3     4     1     2     3
100.33     3     4     5     2     4     6
100.66     2     4     0     5     0     7
100.99     0     0     5     6     3     8

Upvotes: 2

Sundeep
Sundeep

Reputation: 23667

With perl

$ perl -lane 'print join "\t", "", map {20.00+$_*0.33} 0..$#F if $.==1;
              print join "\t", 100+(0.33*$i++), @F' ip.txt
        20      20.33   20.66   20.99   21.32   21.65
100     2       3       4       1       2       3
100.33  3       4       5       2       4       6
100.66  2       4       0       5       0       7
100.99  0       0       5       6       3       8
  • -a to auto-split input on whitespaces, result saved in @F array
  • if $.==1 for the first line of input
    • map {20.00+$_*0.33} 0..$#F iterate based on size of @F array, and for each iteration, we get a value based on equation inside {} where $_ will be 0, 1, etc upto last index of @F array
    • print join "\t", "", map... use tab separator to print empty element and results of map
  • For all the lines, print contents of @F array pre-fixed with results of 100+(0.33*$i++) where $i will be initially 0 in numeric context. Again, tab is used as separator while joining these values


Use sprintf if needed for formatting, also $, can be initialized instead of using join

perl -lane 'BEGIN{$,="\t"; $st=0.33}
            print "", map { sprintf "%.2f", 20+$_*$st} 0..$#F if $.==1;
            print sprintf("%.2f", 100+($st*$i++)), @F' ip.txt

Upvotes: 1

RomanPerekhrest
RomanPerekhrest

Reputation: 92854

Awk solution:

awk 'NR == 1{ 
         long = 20.00; lat = 100.00; printf "%12s%.2f", "", long; 
         for (i=1; i<NF; i++) { long += 0.33; printf "\t%.2f", long } print "" }
     NR > 1{ lat += 0.33 }
     { 
         printf "%.2f%6s", lat, ""; 
         for (i=1; i<=NF; i++) printf "\t%d", $i; print "" 
     }' file

Upvotes: 1

RavinderSingh13
RavinderSingh13

Reputation: 133528

Following awk may also help you on same.

awk -v col=100 -v row=20 'FNR==1{printf OFS;for(i=1;i<=NF;i++){printf row OFS;row=row+.33;};print ""} {col+=.33;$1=$1;print col OFS $0}' OFS="\t"  Input_file

Adding non one liner form of above solution too now:

awk -v col=100 -v row=20 '
FNR==1{
  printf OFS;
  for(i=1;i<=NF;i++){
    printf row OFS;
    row=row+.33;
};
  print ""
}
{
  col+=.33;
  $1=$1;
  print col OFS $0
}
' OFS="\t"  Input_file

Upvotes: 1

Related Questions