Как получить уникальные значения от столбца к строке - PullRequest
0 голосов
/ 28 декабря 2018

У меня есть входной файл, такой как:

> 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

Я не могу напечатать все уникальные значения из столбца 1 перед столбцом 2

Ответы [ 6 ]

0 голосов
/ 30 декабря 2018

Вот 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

ПРИМЕЧАНИЕ. Так как awk и perl используют ассоциативный массив, напечатанный порядок, вероятно, будет отличаться от порядка, в котором элементы встречаются в файле.

0 голосов
/ 30 декабря 2018

Использование 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
0 голосов
/ 28 декабря 2018

sort Assisted 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 для отложенной инициализации разделителя, чтобы пропустить первый.

0 голосов
/ 28 декабря 2018

Использование 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
0 голосов
/ 28 декабря 2018

Вот еще один.Он добавляет $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 "($|,)")?"" null, если match найдет соответствующее значение
  • :(a[$2]==""?"":",")$1) или запятую, если необходимо, и значение
0 голосов
/ 28 декабря 2018

Для 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 won 't печатать новую строку, поэтому используйте print "", чтобы, наконец, добавить новую строку.

...