CSV에서 중복된 열 값 찾기

CSV에서 중복된 열 값 찾기

행당 레코드만 있는 대형 csv 파일에서 중복 ID를 찾으려고 하는데 중복 항목을 찾는 조건이 첫 번째 열입니다.<id>,<value>,<date>

예제.csv

11111111,high,6/3/2019
22222222,high,6/3/2019
33333333,high,6/3/2019
11111111,low,5/3/2019
11111111,medium,7/3/2019

원하는 출력:

11111111,high,6/3/2019
11111111,low,5/3/2019
11111111,medium,7/3/2019

출력은 순차적일 필요는 없습니다.

답변1

AWK 사용:

awk -F, 'data[$1] && !output[$1] { print data[$1]; output[$1] = 1 }; output[$1]; { data[$1] = $0 }'

각 행을 살펴보고 다음과 같이 동작합니다.

  • 첫 번째 열의 값을 본 경우 해당 값과 일치하는 행을 출력하고 기억된 행을 출력해야 합니다.
  • 현재 행의 첫 번째 열이 출력하려는 ​​내용과 일치하면 현재 행이 출력됩니다.
  • 첫 번째 열에 입력된 현재 행을 저장합니다.

답변2

모든 ID의 길이가 동일한 경우(예제에서는 8자) sortGNU를 사용하여 전체 작업을 수행할 수 있습니다 uniq.

$ sort file | uniq -Dw 8
11111111,high,6/3/2019
11111111,low,5/3/2019
11111111,medium,7/3/2019

길이가 다른 경우에도 이 방법을 사용할 수 있지만 조금 더 복잡해집니다.

$ tr ',' ' ' < file | sort  | rev | uniq -f2 -D | rev | tr ' ' ','
11111111,high,6/3/2019
11111111,low,5/3/2019
11111111,medium,7/3/2019

답변3

awk -F, '$1 in m { print m[$1]$0; m[$1]=""; next } 
                 { m[$1]=$0 "\n" }' ex

답변4

GNU sed이는 확장된 정규식 구성을 활용하여 수행할 수 있습니다. 먼저 파일을 패턴 공간에 로드한 다음 패턴 공간의 시작 부분에서 중복되지 않은 모든 줄을 제거합니다. 또한 \n\n반복되는 라인을 덮어쓰는 패턴 공간의 끝에 플래그가 배치됩니다. 따라서 플래그가 패턴 공간의 시작 부분에 버블링되면 => 작업이 종료되고 이제 패턴 공간에서 플래그를 제거하고 stdout으로 인쇄할 수 있습니다.

$ sed -Ee '
   $!{
      N;s/^/\n/
      $s/$/\n\n/;D
   }
   /^([^,\n]*),[^\n]*\n(.*\n)?\1,/!D
   s/^([^\n]*)(.*)/\2\1\n/;/^\n\n/!D
   s/^\n\n//;s/\n$//
' inp

여기에 POSIX-sed문제를 해결하는 버전과 다른 방법이 있습니다. 즉, 우리는 스키마나 예약된 공간의 어느 시점에서도 전체 파일을 유지하지 않습니다. 중복 라인이 보이자마자 표준 출력으로 인쇄되고 참조 라인이 표시되고 인쇄됩니다. 다음에 중복 라인을 볼 때 인쇄하고 싶지 않기 때문에 표시됩니다.

$ sed -ne '
   H;g;y/\n_/_\n/
   /.*_\([^,_]*\)\(,[^_]*\)\[0]_\(.*_\)\{0,1\}\1,[^_]*$/{
      s//\1\2/;y/_\n/\n_/;p
      g;s/.*\n//p;g;y/\n_/_\n/
      s/\(.*_\([^,_]*\),[^_]*\)\[0]\(_\(.*_\)\{0,1\}\)\2,[^_]*$/\1[1]\3/
      s/_$//;y/_\n/\n_/;bh
   }
   /.*_\([^,_]*\)\(,[^_]*\)\[1]_\(.*_\)\{0,1\}\1,[^_]*$/{
      s/.*_//;y/_\n/\n_/;p
      g;s/\(.*\)\n.*/\1/;bh
   }
   y/_\n/\n_/;s/$/[0]/;:h;h
' inp

이는 Perl배열 해시의 행을 유지하는 문제에 대한 기본적인 솔루션입니다. 중복 행이 보이면 배열을 인쇄하고 비운 다음 중복 행을 인쇄합니다.

$ perl -F, -lane '
   push(@{$h{$F[0]}},$_),next if ! exists $h{$F[0]};
   print for splice(@{$h{$F[0]}}),$_;
' inp

산출:

11111111,high,6/3/2019
11111111,low,5/3/2019
11111111,medium,7/3/2019

관련 정보