여러 열을 정렬 -u(또는 정렬 | uniq)하지만 세 번째 열에 정보를 유지하고 유지된 행에 추가하시겠습니까?

여러 열을 정렬 -u(또는 정렬 | uniq)하지만 세 번째 열에 정보를 유지하고 유지된 행에 추가하시겠습니까?

다음과 같은 형식을 취하려고 합니다.

a     b     hello
a     b     goodbye
g     g     test
a     c     I say

열 3의 정보를 잃지 않고 열 1과 2의 각 고유 항목에 대해 테이블을 하나의 행으로 축소합니다. 3열의 값은 쉼표로 구분된 목록으로 추가될 수 있습니다. 결과는 다음과 같습니다.

a     b     hello, goodbye
a     c     I say
g     g     test

어디서부터 시작해야할지 모르겠습니다. 을 사용하면 sort -k1,1 -k2,2 -u다음과 같은 결과를 얻습니다.

a     b     hello
a     c     I say
g     g     test

"Goodbye" 항목을 잃어버렸는데 보관하고 싶습니다. 위의 예에 표시된 것처럼 3열의 데이터를 삭제하지 않는 방법을 아는 사람이 있나요?

답변1

독립형 방법은 모르지만 sortawk를 사용하여 값을 "축소"한 다음 정렬할 수 있습니다.

$ awk -F'\t' '
    BEGIN{OFS=FS} 
    {k = $1 FS $2} 
    {a[k] = a[k] == "" ? $3 : a[k] "," $3} 
    END{for (k in a) print k,a[k]}
 ' file | sort
a       b       hello,goodbye
a       c       I say
g       g       test

최신 버전의 GNU awk에서는 다음을 설정하여 외부 정렬을 피하기 위해 배열 순회 순서를 설정할 수 있습니다 PROCINFO.

awk -F'\t' '
  BEGIN{OFS=FS} 
  {k = $1 FS $2} 
  {a[k] = a[k] == "" ? $3 : a[k] "," $3} 
  END{PROCINFO["sorted_in"]="@ind_str_asc"; for (k in a) print k,a[k]}
' file

또는 GNU datamash를 사용하십시오.

datamash groupby 1,2 collapse 3 <file

또는 더 자세한 (그러나 더 유연한) Miller

mlr --nidx --fs tab nest --implode --values --across-records --nested-fs , -f 3  file

답변2

Bash에서 임시 파일을 사용하는 2단계 솔루션:

$ cat table.csv
a       b       hello
a       b       goodbye
g       g       test
a       c       I say

$ WD=$(mktemp -d) ; while read K1 K2 V ; do echo -n ",$V" >>$WD/$K1:$K2 ; done <table.csv

$ sort -k1,1 -k2,2 -u table.csv | while read K1 K2 V ; do echo $K1 $K2 $(sed 's/^.//' <$WD/$K1:$K2) ; done
a b hello,goodbye
a c I say
g g test

해결 방법의 요점은 >>정렬하기 전에 동일한 키에 대한 값을 수집하기 위해 Shell Append Redirect()를 사용하는 것입니다.

답변3

함수를 사용하여 수행할 수도 있습니다 sed(죄송하지만 사람이 실제로 읽을 수는 없습니다).

echo "a      b       hello
a       c       goodbye
g       g       foo
a       c       bar
a       b       test
a       c       I say" | sort -k1,1 -k2,2 | sed ":a N; s/\([^\t]*\)\t\([^\t]*\)\t\([^\t]*\)\n\1\t\2\t\([^\t]*\)/\1\t\2\t\3,\4/; ta; P; D; ba;"

출력은 예상대로입니다.

a       b       hello,test
a       c       bar,goodbye,I say
g       g       foo
  • 먼저 정렬한 다음 sed교체를 사용하세요 uniq.
  • N;sed1개 행 대신 2개 행(또는 "1개 추가 행")을 처리 해야 합니다 .
  • s/.../.../두 줄을 병합합니다.
    • \([^\t]*\)하나의 열을 차지합니다(스트립 없이 가능한 한 많은 문자 \t).
    • \t탭 문자(구분자)입니다.
    • \n\t\1\t\2\t두 번째 행에 두 개의 유사한 첫 번째 열이 있는지 확인하세요.
    • /\1\t\2\t\3,\4/2개의 행을 첫 번째와 두 번째 열이 동일한 하나의 행으로 변환하고 세 번째 열을 병합합니다.
  • :a ... ta;루프 와 같습니다 while( work 교체 시 다시 실행됨 s).
  • P; D;여기에 있으면 s실패하므로 패턴 공간에 두 개의 "다른"(첫 번째 또는 두 번째 열에) 줄이 있습니다. P첫 번째 줄(병합된 줄이 포함될 수 있음)을 인쇄하고 D인쇄한 줄을 제거합니다.
  • ba;행을 읽을 수 있는 동안 반복합니다(현재 패턴 공간에는 1개의 행이 있습니다).

관련 정보