2014-12-23 14 views
6

Dato questo input di esempio:Calcolo percentuali in numero arbitrario di colonne

ID  Sample1  Sample2  Sample3 
One  10   0   5 
Two  3   6   8 
Three 3   4   7 

I necessari per produrre questo output utilizzando AWK:

ID Sample1 Sample2 Sample3 
One 62.50 0.00 25.00 
Two 18.75 60.00 40.00 
Three 18.75 40.00 35.00 

Così ho risolto:

function percent(value, total) { 
    return sprintf("%.2f", 100 * value/total) 
} 
{ 
    label[NR] = $1 
    for (i = 2; i <= NF; ++i) { 
     sum[i] += col[i][NR] = $i 
    } 
} 
END { 
    title = label[1] 
    for (i = 2; i <= length(col) + 1; ++i) { 
     title = title "\t" col[i][1] 
    } 
    print title 
    for (j = 2; j <= NR; ++j) { 
     line = label[j] 
     for (i = 2; i <= length(col) + 1; ++i) { 
      line = line "\t" percent(col[i][j], sum[i]) 
     } 
     print line 
    } 
} 

Funziona correttamente in GNU AWK (awk in Linux, gawk in BSD), ma non in BSD AWK, dove ottengo questo errore:

$ awk -f script.awk sample.txt 
awk: syntax error at source line 7 source file script.awk 
context is 
      sum[i] += >>> col[i][ <<< 
awk: illegal statement at source line 7 source file script.awk 
awk: illegal statement at source line 7 source file script.awk 

sembra che il problema è con gli array multidimensionali. Mi piacerebbe far funzionare questo script anche in BSD AWK, quindi è più portatile.

C'è un modo per cambiare questo per farlo funzionare in AWD BSD?

+0

Risposta semplice - provare nawk. Dovrebbe essere parte dell'installazione di BSD. Alcune versioni di awk sono veramente vecchie. –

risposta

4

Provare a utilizzare la forma pseudo-2-dimensionale. Invece di

col[i][NR] 

uso

col[i,NR] 

Questo è un array 1-dimensionale, la chiave è la stringa concatenata: i SUBSEP NR

3

s' @glenn risposta mi ha fatto sulla strada giusta. Ci è voluto un po 'più di lavoro però:

  • Utilizzare col[i, NR] fatto trattare con i titoli di colonna fastidiosi. Ha aiutato molto a rimuovere il buffering dei titoli delle colonne e li ha stampati immediatamente dopo aver letto
  • length(col) + 1 non era più utilizzabile nella condizione del ciclo finale, poiché l'uso di col[i, j] ha reso i loop infiniti. Per aggirare il problema, ho potuto sostituire length(col) + 1 con semplicemente NF

Ecco l'implementazione finale, che ora funziona sia in versione GNU e BSD di AWK:

function percent(value, total) { 
    return sprintf("%.2f", 100 * value/total) 
} 
BEGIN { OFS = "\t" } 
NR == 1 { gsub(/ +/, OFS); print } 
NR != 1 { 
    label[NR] = $1 
    for (i = 2; i <= NF; ++i) { 
     sum[i] += col[i, NR] = $i 
    } 
} 
END { 
    for (j = 2; j <= NR; ++j) { 
     line = label[j] 
     for (i = 2; i <= NF; ++i) { 
      line = line OFS percent(col[i, j], sum[i]) 
     } 
     print line 
    } 
} 
Problemi correlati