다른 열의 값을 기준으로 중복 제거


9

다음 파일이 있습니다.

AA,true
AA,false
BB,false
CC,false
BB,true
DD,true

중복을 찾고 열 값이 인 줄을 제거하려고합니다 true.

출력으로 다음과 같아야합니다.

AA,false
BB,false
CC,false
DD,true

2
그래서 .. true첫 번째 열의 첫 번째 인스턴스 인 경우 에만 유지 합니까?
DopeGhoti

1
@RomanPerekhrest 아마 uniq 항목이고 "있는 그대로"인쇄되어 있습니다.
George Vasiliou

DD, true가 중복되지 않기 때문에 @RomanPerekhrest 우리는 DD, false와 다른 줄이 없습니다.
Hani Gotc

AA,true AA,false AA,false AA,false이 경우 어떤 결과를 가져야합니까? 해당 행이 중복되어 true동시에 포함되어 있는 경우에만 해당 행을 제거해야합니다 . false어떤 경우에도 모든 행은 그대로 유지해야합니다. 즉,이 경우에만 AA, true제거됩니다. 그러나 모든 대답은 한 줄만 남습니다 AA,false. 그냥 흥미로운 :)
MiniMax

답변:


9
awk -F, '$2 == "false" {data[$1]=$2 } $2=="true" { if ( data[$1]!="false" ) { data[$1]=$2 } } END { OFS=","; for (item in data) { print item,data[item] }}' input

설명을 위해 스크립트를 세로로 확장하려면

BEGIN {
   FS=","         # Set the input separator; this is what -F, does.
}
$2 == "false" {    # For any line whose second field is "false", we
   data[$1]=$2     # will use that value no matter what.
}
$2=="true" {                    # For lines whose second field is "true",
   if ( data[$1]!="false" ) {   # only keep if if we haven't yet seen a
      data[$1]=$2               # "false"
   }
}
END {                           # Now that we have tabulated our data, we
   OFS=","                      # can print it out by iterating through 
   for (item in data) {         # the array we created.
      print item,data[item]
   }
}

@DopeGhoti 잘 설명했다! 이것에 대한 +1이 있습니다.
발렌틴 바즈 라미

14

간단한 버전 :

sort input.txt | awk -F, '!a[$1]++'

"false"는 "true"보다 알파벳순으로 정렬되며 여기서 Awk 명령은 각각의 고유 한 첫 번째 필드 값에 대해서만 첫 번째 행만 유지합니다.

"false"대신 "true"를 유지하려면 역 정렬하여 동일한 Awk 명령에 전달한 후 나중에 다시 정렬하십시오.


1
또한 -u옵션을 사용할 수있는 경우sort input.txt | sort -t, -u -k1,1
Sundeep

2
@Sundeep 왜 두 sort통화를 사용 합니까? 왜 안돼 sort -ut, -k1,1 input.txt ?
terdon

2
@terdon -u은 중복 된 파일 중 입력 파일에서 찾은 첫 번째 줄을 유지 하기 때문에 ... 주어진 경우 입력을 -u적용 하기 전에 입력을 정렬해야 합니다 ... 예 : 주어진 샘플에서 처음 표시되기 때문에 AA,true대신 인쇄됩니다 AA,false. awk -F, '!a[$1]++'
혼자서도이

5
perl -F, -lane '
   exists $h{$F[0]} or $h[$h{$F[0]}=@h]=$_;
   $h=$_; /,false$/ or $_=$h for $h[$h{$F[0]}];
   END{ print for @h; }
' duplicates.file

데이터 구조 :

  • %h키가 첫 번째 필드 (AAA, BBB, CCC 등) 인 해시 와 해당 값은 키가 발생한 순서를 나타내는 숫자입니다. 따라서, 예를 들어, 키 AAA => 0, 키 BBB => 1, 키 CCC => 2입니다.
  • @h인쇄 순서에 포함 된 선이 요소 인 배열 . 따라서 데이터에서 true와 false가 모두 발견되면 false 값이 배열로 이동합니다. OTW, 한 가지 유형의 데이터가 있다면 이것이 존재할 것입니다.

또 다른 방법은 GNU sed를 사용하는 것입니다.

sed -Ee '
   G
   /^([^,]*),(false|true)\n(.*\n)?\1,\2(\n|$)/ba
   /^([^,]*)(,true)\n(.*\n)?\1,false(\n|$)/ba
   /^([^,]*)(,false)\n((.*\n)?)\1,true(\n|$)/{
      s//\3\1\2\5/;h;ba
   }
   s/([^\n]*)\n(.*)$/\2\n\1/;s/^\n*//
   h;:a;$!d;g
' duplicates.file

위의 GNU 코드에 대한 POSIX 코드는 다음과 같습니다.

sed -e '
   G

   /^\([^,]*\),\(false\)\n\(.*\n\)\{0,1\}\1,\2$/ba
   /^\([^,]*\),\(false\)\n\(.*\n\)\{0,1\}\1,\2\n/ba

   /^\([^,]*\),\(true\)\n\(.*\n\)\{0,1\}\1,\2$/ba
   /^\([^,]*\),\(true\)\n\(.*\n\)\{0,1\}\1,\2\n/ba

   /^\([^,]*\),true\n\(.*\n\)\{0,1\}\1,false$/ba
   /^\([^,]*\),true\n\(.*\n\)\{0,1\}\1,false\n/ba

   /^\([^,]*\)\(,false\)\n\(\(.*\n\)\{0,1\}\)\1,true$/{
      s//\3\1\2/
      h
      ba
   }
   /^\([^,]*\)\(,false\)\n\(\(.*\n\)\{0,1\}\)\1,true\n/{
      s//\3\1\2\n/
      h
      ba
   }

   y/\n_/_\n/
   s/\([^_]*\)_\(.*\)$/\2_\1/;s/^_*//
   y/\n_/_\n/

   h;:a;$!d;g
' duplicates.file

설명

  • 이 방법에서는 최종적으로 인쇄 될 결과를 보류 공간에 저장합니다.
  • 판독 된 모든 라인에 대해, 홀드 공간의 기존 상태에 대한 현재 라인의 검사를 위해 홀드 공간을 패턴 공간에 추가합니다.
  • 이제이 비교 중에 5 가지 일이 발생할 수 있습니다.
    • a) 현재 줄은 보류 줄 & false : false 어딘가에 일치합니다.
      • [조치] 동일한 잘못된 상태가 발견되었으므로 아무 것도 수행하지 마십시오.
    • b) 현재 줄은 보류 줄의 어딘가와 일치합니다. & true : true.
      • [조치] 동일한 참 상태가 발견되었으므로 아무 것도 수행하지 마십시오.
    • c) 현재 라인은 홀드 라인의 어딘가와 일치합니다. & true : false.
      • [조치] 잘못된 상태가 이미 있으므로 아무 것도하지 마십시오.
    • d) 현재 줄은 보류 줄의 어딘가와 일치합니다. & false : true.
      • [조치] 여기에는 실제 위치와 정확히 같은 위치에서 잘못된 라인을 교체해야한다는 점에서 약간의 작업이 필요합니다.
    • e) 현재 라인은 홀드 라인의 어느 곳과도 일치하지 않습니다.
      • [행동] 현재 줄을 끝으로 이동하십시오.

결과

AA,false
BB,false
CC,false
DD,true

3

각 입력 줄에 대해 두 번째 필드의 값을 연관 배열에 저장합니다 a(첫 번째 필드를 배열의 키로 사용). 해당 키 의 값 false을 아직 저장하지 않은 경우 에만 해당 합니다 . ,입력 및 출력 필드 구분 기호에 모두 사용하십시오 . 모든 입력 라인을 읽은 후 배열을 인쇄하십시오.

$ awk -F, -v OFS=, 'a[$1] != "false" { a[$1] = $2 };
                    END { for (i in a) {print i,a[i]} }' truefalse.txt
AA,false
BB,false
CC,false
DD,true

이 버전과 DopeGhoti 버전의 중요한 차이점은이 버전은의 값에 전혀 관심이없고의 값 $2에만 관심이 있다는 것입니다 a[$1].


1

2 패스 sort솔루션

sort -k1,1 -k2,2 -t, file | sort -k1,1 -t, -u

첫번째 sort필드에 의해 클러스터에 기록을 전달 1하여 false선행 레코드 true공통 필드 공유 레코드의 각각의 블록에 대한 1값. 두 번째 sort패스는 필드 1예의 내에서 각 고유 한 값에 대해 하나의 레코드를 생성하도록 설정됩니다 -u. 이후 -u안정된 정렬을 의미한다, 따라서 수득 한 레코드 필드 내의 각각의 고유 값에 대해 발생 제이다 레코드 1에 기록 인 - false인해 제에 의해 수행 된 작업 내지 제 필드 sort패스

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.