awk处理案例二十五--指定列去重问题
场景
其实之前有人问过的,算是月经贴了~不过想问个复杂点的。比如一个文本,他只是第二第三列相同,其他列都不一样,我想把相同的变成一行,不同的合并起来怎么做呢?
ex:
然后得到:
原帖地址: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;

浙公网安备 33010602011771号