【问题标题】:How to get the unique values from column to row如何从列到行获取唯一值
【发布时间】:2019-05-26 05:46:15
【问题描述】:

我有一个像这样的输入文件:

> 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 列中的所有唯一值

【问题讨论】:

  • 使用编辑器中的{} 按钮或在数据和代码前添加四个空格。

标签: unix awk solaris


【解决方案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

【讨论】:

  • 哦。这是一个很棒的程序。
【解决方案2】:

使用 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

【讨论】:

  • 谢谢 .. 它帮助了我。
  • 很高兴它对您有所帮助.. 请考虑接受答案
【解决方案3】:

对于 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 ""追加一个新行。

【讨论】:

    【解决方案4】:

    这是另一个。它将$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 找到匹配值,则为 null
    • :(a[$2]==""?"":",")$1) 或逗号(如果需要)和值

    【讨论】:

      【解决方案5】:

      这是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:

      $ 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 都使用关联数组,因此打印的顺序可能与文件中元素的出现顺序不同。

      【讨论】:

      • 这是哪个 awk?.. 我收到语法错误 $ awk -F, '{a[$2][$1]++ } ' jeevan.txt awk: {a[$2][$1] ++ } awk: ^ 语法错误
      • @stack0114106 你所展示的 ++ 不在他们的帖子中(与 Perl 混淆了?)—— that 是非法的。他们的代码为我运行。
      • @stack0114106 好的 .. 我建议然后删除(所有)这些 cmets?
      【解决方案6】:

      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 用于惰性分隔符初始化以跳过第一个。

      【讨论】:

      • 由于文件已排序,您可以比较上一个和当前记录并在阅读sort -t, -u -k2 -k1,1 file | awk -F, '{ if(prev!=$2) { x=NR&gt;1?"\n":""; printf("%s%s %s",x,$2,$1) } else { printf(",%s",$1) } prev=$2 } END { print "" }'行时​​打印它们
      猜你喜欢
      • 2012-01-12
      • 1970-01-01
      • 2022-06-22
      • 1970-01-01
      • 1970-01-01
      • 2019-12-08
      • 1970-01-01
      相关资源
      最近更新 更多