用awk计算sum,count,distinct count字段

时间:2013-03-14 17:49:19

标签: shell awk

我有一个这样的文本文件:

A   B   C   D   E
----------------------  
x   x   e   2   10
y   y   g   1   8 
z   o   e   2   9 
o   o   q   1   10
p   z   e   3   22
x   x   e   1   11
z   o   a   1   24
y   z   b   1   25

我想使用awk执行与此SQL相同的操作:

select A, 
       B, 
       count(distinct C), 
       sum(D),
       sum(case when E>20 then E else 0 END) 
  from test 
 group by A,B

输出:

A   B  count(distinct C)    sum(D)  sum(case when E>20 then E else 0 END) 
-------------------------------------------------------
o   o   1       1       0
p   z   1       3       22
x   x   1       3       0
y   y   1       1       0
y   z   1       1       25
z   o   2       3       24

这是我的解决方案,但不完整的部分未完成:

awk '
{
    idx4[$1"|"$2]=idx4[$1"|"$2]+$4;
    idx5[$1"|"$2]=$5>20?idx5[$1"|"$2]+$5:idx5[$1"|"$2]
} 
END {
    for (i in idx4) print i, idx4[i], idx5[i]
}' OFS="\t" test

=============================================== ==============================

我已经完成了几个小时,这是我的代码:

    {
        if (idx3[$1"|"$2, $3] == 0) {
            idx3[$1"|"$2, $3]+=1;
        }
        idx4[$1"|"$2]=idx4[$1"|"$2]+$4;
        idx5[$1"|"$2]=$5>20?idx5[$1"|"$2]+$5:idx5[$1"|"$2]
    } 
    END {
        for (j in idx3) {
            split(j, idx, SUBSEP)
            count[idx[1]]++
        }
        for (i in idx4) {
            print i, count[i], idx4[i], idx5[i] 
        }
    } OFS="\t"

@Scrutinizer在下面给出了一个更易读的代码,我认为这样更好。

3 个答案:

答案 0 :(得分:1)

试试这个(类似于你自己的解决方案):

awk '
  NR<3{
    next
  }

  {
    i=$1 OFS $2
    D[i]+=$4
  }

  !A[i,$3]++{
    C[i]++
  }

  $5>20{
    E[i]+=$5
  }

  END{
    for(i in D)print i, C[i], D[i], E[i]+0
  }
' OFS='\t' infile

NR<3用于跳过两个标题行。如果它们不在输入文件中,您可以将该部分保留。

答案 1 :(得分:1)

请尝试这个脚本,我测试过它可以按预期结果输出结果。

awk '
{
    if( NR<3) {next}

    idx4[$1"|"$2]=idx4[$1"|"$2]+$4;
    idx5[$1"|"$2]=$5>20?idx5[$1"|"$2]+$5:idx5[$1"|"$2]

    if( index(TR[$1"|"$2],$3)==0 )
    {
         TR[$1"|"$2] = TR[$1"|"$2]"|"$3;
         TRD[$1"|"$2] +=1;
    }
} 
END {
    for (i in idx4) print i, TRD[i], idx4[i], idx5[i]+0
}' OFS="\t" test

答案 2 :(得分:0)

$ gawk '{ a[$1,$2]["C"][$3]; a[$1,$2]["D"]+=$4; a[$1,$2]["E"]+=($5>20 ? $5:0) }
END { 
    PROCINFO["sorted_in"] = "@ind_str_asc"
    for ( i in a) { 
        split(i, b, SUBSEP) 
        print b[1], b[2], length(a[i]["C"]), a[i]["D"], a[i]["E"] 
    }
}' OFS='\t' file
o       o       1       1       0
p       z       1       3       22
x       x       1       3       0
y       y       1       1       0
y       z       1       1       25
z       o       2       3       24