如何从列到行获取唯一值

时间:2018-12-28 11:29:45

标签: unix awk solaris

我有一个输入文件,例如:

> cat test_mfd_1
16,281474976750348
17,281474976750348
16,281474976750348
17,281474976750348
16,281474976749447
17,281474976749447
16,281474976749447
17,281474976749447

我需要这样的输出:

281474976750348 16,17
281474976749447 16,17

第2列和第1列均具有重复的值。但是作为o / p,它应该在第2列中找到唯一值,并在行中打印所有相应的唯一值。

我正在使用awk,并且得到如下所示的o / p。

awk -F, '{a[$2]=$1;} END {for(i in a) print i" "a[i];}' test_mfd_1
281474976749447 17
281474976750348 17

我无法在第2列的前面打印第1列的所有唯一值

6 个答案:

答案 0 :(得分:1)

对于GNU awk:

awk -F, '{a[$2][$1]} END {for(i in a) {printf i; first=1; for (j in a[i])  if (first) {printf " " j; first=0;} else printf "," j; print ""} }' test_mfd_1
#=> 281474976749447 16,17
#=> 281474976750348 16,17

改进您的尝试。
这个想法是使用二维数组和一个内部for循环。
printf不会打印换行符,因此请使用print ""最后添加新行。

答案 1 :(得分:1)

这是另一个。它将以逗号分隔的$1值附加到a[$2],但首先使用match()来检查该值是否已经存在:

$ awk -F, '{
    a[$2]=a[$2] (match(a[$2],"(^|,)" $1 "($|,)")?"":(a[$2]==""?"":",")$1)
} 
END {
    for(i in a)
        print i,a[i]
} ' file
281474976749447 16,17
281474976750348 16,17

解释一下:

  • a[$2]=a[$2] (...追加到数组
  • 如果match(a[$2],"(^|,)" $1 "($|,)")?""找到匹配的值,
  • match为空
  • :(a[$2]==""?"":",")$1)或逗号(如果需要)和值

答案 2 :(得分:1)

使用GNU Datamash

$ datamash --sort -t, -g 2 unique 1 < file
281474976749447,16,17
281474976750348,16,17

如果您坚持使用空格:

$ datamash --sort -t, -g 2 unique 1 < file | sed 's/,/ /'
281474976749447 16,17
281474976750348 16,17

答案 3 :(得分:1)

使用Perl

$ cat jeevan.txt
16,281474976750348
17,281474976750348
16,281474976750348
17,281474976750348
16,281474976749447
17,281474976749447
16,281474976749447
17,281474976749447

$ perl -F, -lane ' $kv{$F[1]}{$F[0]}++; END { while(my($x,$y) = each(%kv)) { print "$x ",join(",",keys %$y) } }' jeevan.txt
281474976749447 16,17
281474976750348 16,17

$ perl -F, -lane ' $kv{$F[1]}{$F[0]}++; END { print "$_ ",join(",",keys %{$kv{$_}}) for(keys %kv) } ' jeevan.txt
281474976749447 16,17
281474976750348 16,17

$ perl -F, -lane ' push @{$kv{$F[1]}},$F[0]; END { for(keys %kv) { %p=map{ $_ => 1} @{$kv{$_}} ; print "$_ ",join(",", keys %p) } } ' jeevan.txt
281474976749447 17,16
281474976750348 16,17

$ perl -F, -lane ' push @{$kv{$F[1]}},$F[0]; END { for my $a (keys %kv) { @p=grep{ !$s{$a}{$_}++ } @{$kv{$a}} ; print "$a ",join(",", @p) } } ' jeevan.txt
281474976749447 16,17
281474976750348 16,17

$ perl -F, -lane ' push @{$kv{$F[1]}},$F[0]; END { for my $a (keys %kv) { print "$a ",join(",", grep{ !$s{$a}{$_}++ } @{$kv{$a}}) } } ' jeevan.txt
281474976750348 16,17
281474976749447 16,17

由于它类似于SQL,因此您也可以使用sqlite

$ cat ./sqllite_unique.sh
#!/bin/sh
sqlite3 << EOF
create table t1(a,b);
.separator ','
.import $1 t1
select b|| ' ' || group_concat(distinct a) from t1 group by b;
EOF

$ ./sqllite_unique.sh jeevan.txt
281474976749447 16,17
281474976750348 16,17

答案 4 :(得分:1)

这里是Perl

$ perl -F, -lanE '$HoH{$F[1]}{$F[0]}++; 
                  END{for (keys %HoH) {
                         say "$_ ", join(", ", keys %{$HoH{$_}}); }}' file
281474976749447 16, 17
281474976750348 17, 16

这是个可怕的事情

$ awk -F, '{a[$2][$1]} 
           END{ for (e in a){
                  s=""
                  for (x in a[e]) s=s?s ", " x:x
                  print e, s}}' file
281474976749447 16, 17
281474976750348 16, 17

注意:由于awkperl都使用关联数组,因此打印顺序可能与文件中元素遇到的顺序不同。

答案 5 :(得分:0)

sort辅助awk

$ sort -t, -u -k2 -k1,1 file | 
  awk -F, '{a[$2]=a[$2] sep[$2] $1; sep[$2]=FS} END{for(k in a) print k,a[k]}'

281474976749447 16,17
281474976750348 16,17

sep用于延迟分隔符的初始化,以跳过第一个。