按照第一列中的值排列列中的值

时间:2019-01-11 19:21:43

标签: perl unix awk sed solaris

我有一个包含以下数据的文件

cat text.txt
281475473926267,46,47
281474985385546,310,311
281474984889537,248,249
281475473926267,16,17
281474985385546,20,28
281474984889537,112,68

第一列中的值在某些地方重复 我想要如下所示的

cat output.txt
281475473926267 16,17,46,47
281474985385546 20,28,310,311
281474984889537 68,112,248,249

它应该先打印第1列的uniq值,然后打印空格,然后再在一行中按升序打印另一列的相应值。

我在下面尝试过

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

281474984889537 112,248
281474985385546 310,20
281475473926267 46,16

在这里,我无法在第一列中的值前面打印所有值

对于281474984889537,它应打印68,112,248,249,但仅打印112,248

我也不知道如何按升序排列它们。

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

281474984889537 112,248
281474985385546 310,20
281475473926267 46,16

在这里,我无法在第一列中的值前面打印所有值

4 个答案:

答案 0 :(得分:1)

多步骤

$ awk -F, '{print $1,$2; print $1,$3}' file             | 
  sort -k1n -k2n                                        | 
  awk 'p!=$1{if(p) print p,a[p]; a[$1]=$2; p=$1; next} 
            {a[$1]=a[$1] "," $2} 
       END  {print p,a[p]}'                             | 
  sort -k2n

281475473926267 16,17,46,47
281474985385546 20,28,310,311
281474984889537 68,112,248,249

答案 1 :(得分:0)

对于真正的多维数组,使用GNU awk和sorted_in:

$ cat tst.awk
BEGIN { FS="," }
{
    for (i=2; i<=NF; i++) {
        keyVals[$1][$i]
    }
}
END {
    PROCINFO["sorted_in"] = "@ind_num_asc"
    for (key in keyVals) {
        vals = ""
        for (val in keyVals[key]) {
            vals = (vals == "" ? "" : vals ",") val
        }
        print key, vals
    }
}

$ awk -f tst.awk file
281474984889537 68,112,248,249
281474985385546 20,28,310,311
281475473926267 16,17,46,47

无论您每行有多少个字段,上面的命令都将起作用,并且当重复的值出现在同一键值的多行中时,它将删除重复的值。

答案 2 :(得分:0)

这可能对您有用(GNU sed):

sed -r 'H;x;s/((\n[^\n,]*),[^\n]*)(.*)\2([^\n]*)\n?/\1\4\3/;x;$!d;x;s/.//;:b;h;s/\n.*//;s/[^,]*,//;s/,/\n/g;s/.*/echo "&"|sort -n|paste -sd,/e;G;s/^([^\n]*)\n([^\n,]*),[^\n]*/\2 \1/;P;:c;tc;s/[^\n]*\n//;tb;d' file

该脚本分为两个部分。在处理的第一部分中,通过将同一密钥的值附加到单个密钥,将文件的行保留在内存中并减小大小。在文件末尾,将执行第二部分处理。每行分为两部分,将附加的值排序并重新附加到键上,打印并删除,直到所有行都已处理。

答案 3 :(得分:0)

要更正您的Perl-oneliner,请使用它。

$ cat text.txt
281475473926267,46,47
281474985385546,310,311
281474984889537,248,249
281475473926267,16,17
281474985385546,20,28
281474984889537,112,68

$ cat text.txt | perl -F, -lanE ' @t1=@{$kv{$F[0]}}; push(@t1,@F[1..2]); $kv{$F[0]}=[@t1]; END { while(my($x,$y) = each(%kv)) { print "$x ",join(",",@{$y}) }}'
281474985385546 310,311,20,28
281475473926267 46,47,16,17
281474984889537 248,249,112,68

$

当您有更多的列时,只需将上述单行从1..2更改为1..$#F就可以了。检查一下

$ cat > text2.txt
281475473926267,46,47,49
281474985385546,310,311
281474984889537,248,249,311,677,213
281475473926267,16,17
281474985385546,20,28
281474984889537,112,68,54,78,324,67


$ cat text2.txt | perl -F, -lanE ' @t1=@{$kv{$F[0]}}; push(@t1,@F[1..$#F]); $kv{$F[0]}=[@t1]; END { while(my($x,$y) = each(%kv)) { print "$x ",join(",",@{$y}) }}'
281474984889537 248,249,311,677,213,112,68,54,78,324,67
281474985385546 310,311,20,28
281475473926267 46,47,49,16,17

$