使用UNIX将单元格值传播到列中

时间:2016-03-02 01:14:57

标签: bash awk sed

假设我们有这个文件:

head file

id,name,value
1,Je,1
2,Je,1
3,Ko,1
4,Ne,1
5,Ne,1
6,Je,1
7,Ko,1
8,Ne,1
9,Ne,1

我想要解决这个问题:

id,Je,Ko,Ne
1,1,0,0
2,1,0,0
3,0,1,0
4,0,0,1
5,0,0,1
6,1,0,0
7,0,1,0
8,0,0,1
9,0,0,1

有人知道如何使用awk或sed获取此输出吗?

4 个答案:

答案 0 :(得分:3)

假设name的可能值仅为Je或Ko或Ne,您可以这样做:

awk -F, 'BEGIN{print "id,Je,Ko,Ne"}
         NR==1{ next }
         {je=$2=="Je"?"1":"0"; 
          ko=$2=="Ko"?"1":"0";
          ne=$2=="Ne"?"1":"0";
          print $1","je","ko","ne}' file

如果您想要按照相同的顺序打印值,而不仅限于您的示例字段,您可以这样做:

awk -F, 'BEGIN{OFS=FS; x=1;y=1}
NR==1 { next }

!($2 in oa){ oa[$2]=1; ar[x++]=$2}

{lines[y++]=$0;}

END{
    s="";
    for (i=1; i<x; i++)
         s=s==""?ar[i]:s OFS ar[i];
    print "id" OFS s;   
    for (j=1; j<y; j++){
        split(lines[j], a)
        s=""
        for (i=1; i<x; i++) {
           tt=ar[i]==a[2]?"1":"0"   
           s=s==""?tt:s OFS tt;
         } 
         print a[1] OFS s;
    }
 }
'   file

答案 1 :(得分:1)

这是使用awk的单个调用实现的“双程解决方案”(沿着@Drakosha建议的行)。如果没有关于名称排序的要求,那么实施会更简单一些。

awk -F, '
  # global: n, array a
  function println(ix,name,value,  i,line) { 
    line=ix;
    for (i=0;i<n;i++) {
      if (a[i]==name) {line=line OFS value} else {line=line OFS 0}
    }
    print line;
  }
  BEGIN {OFS=FS; n=0}
  FNR==1 {next}  # skip the header each time
  NR==FNR {if (!mem[$2]) {mem[$2] = a[n++] = $2}; next}
  !s { s="id"; for (i=0;i<n;i++) {s=s OFS a[i]}; print s}
  {println($1, $2, $3)}
  ' file file

答案 2 :(得分:0)

我建议2次传球。

  • 1st将生成第2列的所有可能值(Je,Ko,Ne, ...)。
  • 2nd将能够轻松生成您正在寻找的输出。

答案 3 :(得分:0)

awk -F, 'BEGIN{s="Je,Ko,Ne";print "id,"s}
  NR>1 {m=s; sub($2,1,m); gsub("[^0-9,]+","0",m); print $1","m}' file