awk处理案例二十五--指定列去重问题

场景

其实之前有人问过的,算是月经贴了~不过想问个复杂点的。比如一个文本,他只是第二第三列相同,其他列都不一样,我想把相同的变成一行,不同的合并起来怎么做呢?
ex:

  1. 1     hhh     YYY      1234566
  2. 2     hhh     YYY      166
  3. 3     YYY     hhh      dhu
  4. 4     hhh     YYY      12566
  5. 5     YYY     hhh      888
  6. 6     hhh     YYY      12566(注意这里)
  7. 7     YYY     hhh      d88
  8. 8     YYY     hhh      dhu
复制代码

然后得到:

  1. 1/2/4/6     hhh     YYY      1234566;166;12566;
  2. 3/5/7/8     YYY     hhh      dhu;888;d88;

原帖地址:http://bbs.chinaunix.net/thread-4119085-2-1.html

【分析】:要是最后一列不考虑去重的话,这个问题就很简单!用sql也能实现出来!

    select listagg($1,'/') within group (order by $1)
           ,$2,$3,
           listagg($1,';') within group (order by $1)
           from table group by $2,$3

但是这是文本文件,而且还要去重,这个用sql是实现不了的,还是用文本处理利器awk来实现吧;我的代码如下:

awk '{t=$2 FS $3;if(! a[t]++){s[t]=$1;e[t]=$4}else{s[t]=s[t]"/"$1;e[t]=(t$4 in b)?e[t]:e[t]";"$4}b[t$4]}END{for(i in s)print s[i],i,e[i]}' file
3/5/7/8 YYY hhh dhu;888;d88
1/2/4/6 hhh YYY 1234566;166;12566

【解析】

  题意是根据第2,3列相同,所以我们进行分组;为了后面代码的简洁使用了t来代替第2,3列。我还是讲解下重要的部分。

 !a[t]++:  这个意思是2,3列第一次出现为真;!是取反的意思;例如能匹配上面的第1行和第3行。例如第一行的hhh YYY是第一次出现;第三行的YYY hhh也第一次出现。

  t$4 in b: 这个才是去重的关键;(t$4 in b)?e[t]:e[t]";"$4;这里是一个三目表达式;t$4 in b。我们知道t是代替第2,3列,那么t$4就是第2,3,4列。整体看这3列的值是否是数组b的下标!

 

 与之同时附上星辰大神的代码

 

$ awk -vOFS='\t' '{t=$2"\t"$3;if(!a[t]++)b[++n]=t;if(!c[t,$1]++)d[t]=d[t]!=""?d[t]"/"$1:$1;if(!d[t,$4]++)e[t]=e[t]!=""?e[t]$4";":$4";"}END{for(i=0;i++<n;)print d[b[i]],b[i],e[b[i]]}' i
1/2/4/6 hhh     YYY     1234566;166;12566;
3/5/7/8 YYY     hhh     dhu;888;d88;

 

 

 

 

 

posted @ 2014-01-15 21:27  lottu  阅读(1147)  评论(0)    收藏  举报