각 열마다 고유한 값을 유지합니다(쉼표로 구분).

각 열마다 고유한 값을 유지합니다(쉼표로 구분).

.tsvLinux 시스템에 다양한 유형(문자열, 숫자)의 쉼표로 구분된 값을 포함하는 다음 열이 포함된 (탭으로 구분된 열) 파일이 있습니다 .

col1    col2    
.       NS,NS,NS,true,true      
.       12,12,12,13 
1,1,1,2 door,door,1,1   

고유한 가치를 유지하고 싶습니다(아쉽게도 시도했지만 실패했습니다). 출력은 다음과 같습니다.

col1 col2   
.    NS,true        
.    12,13  
1,2  door,1 

답변1

이는 값 문자열을 정수 인덱스 맵으로 분할한 다음 결합하는 Miller 변형입니다.열쇠쉼표로 구분된 문자열로 돌아가기):

mlr --tsv put 'for (k,v in $*) {
  $[k] =  joink(apply(splitnvx(v,","), func(k,v) {return{v:k}}),",")
}' file.tsv

또는 perl5의 도움으로목록::유틸리티기준 치수:

perl -MList::Util=uniq -F'\t' -lpe '
  $_ = join "\t", map { join ",", uniq split /,/, $_ } @F
' file.tsv

답변2

사용밀러( mlr)는 각 입력 레코드의 탭으로 구분된 필드를 반복하고, 필드 값을 쉼표로 분할하고, 각 결과 문자열을 명명된 맵의 키로 추가하고, 마지막으로 seen재정의할 구분 기호로 쉼표를 사용하여 맵을 연결합니다. 필드 seen:

$ mlr --tsv put 'for (k,v in $*) { seen={}; for (i in splitax(v,",")) { seen[i]=1 } $[k] = joink(seen,",") }' file
col1    col2
.       NS,true
.       12,13
1,2     door,1

Miller의 put표정이 아름답게 인쇄되어 있습니다.

for (k, v in $*) {
    seen = {};
    for (i in splitax(v, ",")) {
        seen[i] = 1
    }
    $[k] = joink(seen, ",")
}

분할 값을 맵의 키로 추가하면 중복이 제거됩니다. 이 splitax()함수는 각 결과 항목의 유형을 추론하지 않고 구분 기호의 문자열을 배열로 분할합니다(문자열이 됩니다). 이 joink()함수는 맵의 키를 함께 연결하여 지정된 구분 기호로 구분된 문자열을 형성합니다. 외부 루프의 k합계 값은 v각각 필드 이름과 해당 값입니다.

답변3

투박한 Perl 접근 방식은 다음과 같습니다.

$ perl -F'\t' -le '
%k=%l={}; 
print join("\t", 
  join(",",grep{++$k{$_}==1}split(/,/,$F[0])), 
  join(",",grep{++$l{$_}==1}split(/,/,$F[1]))
)' file.tsv
col1    col2
.   NS,true
.   12,13
1,2 door,1

답변4

다음 프로그램이 수행됩니다( 배열 (1)awk 작업을 지원 하는 모든 최근 Awk 구현 과 함께 작동해야 함):delete

BEGIN{FS=OFS="\t"}

{
    for (i=1;i<=NF;i++)
    {
        n=split($i,sf,",")
        delete seen
        fld=""

        for (j=1;j<=n;j++)
        {
            if (!seen[sf[j]]++)
            {
                fld=fld (fld?",":"") sf[j]
            }
        }
        $i=fld
    }
    print
}

예를 들어 다음과 같이 저장 dedup.awk하고 호출하세요.

awk -f dedup.awk input.tsv

입력 파일에 대해 작업하십시오.

그러면 \t입력 및 출력 필드 구분 기호가 설정됩니다. 그러면 그럴 것이다

  • for (i=1;i<=NF;i++)행의 모든 ​​필드를 반복( )
  • 각 필드를 하위 필드로 분할( sf),
  • 모든 하위 필드를 반복하고 필드를 임시 변수로 재조립 fld하지만 아직 필드에 표시되지 않은 하위 필드 값만 추가합니다. 배열에 레코드를 저장합니다 seen.
  • 마지막으로 재조립된 필드를 fld현재 필드에 할당합니다.$i
  • 지금까지의 모든 수정 사항을 포함하여 전체 라인을 인쇄합니다.

(1) 요즘 지원이 꽤 널리 퍼져 있음을 암시해준 @EdMorton에게 감사드립니다.

관련 정보