공통기록 확인

공통기록 확인

일부 기록을 신속하게 확인하기 위해 awk가 필요한 작업이 있습니다.

다음과 같이 말해보자:

A1,A2
B1,B2
C1,C2
C2,C1
A1,C1
A1,B1
B1,A1

이는 A#, B#, C# 사이의 상호성만 확인하고 비가역성만 출력하는 가장 좋은 방법입니다. 예를 들어 위의 내용은 다음과 같이 출력되어야 합니다.

A2 -> A1
B2 -> B1

A#은 한 그룹에 속하고 B#은 다른 그룹에 속합니다. A#과 C# 또는 B# 사이의 어떤 종류의 연결을 찾는 데 관심이 없습니다. 대신 As, Bs, Cs 등의 그룹 내에서 검색을 유지하세요.

답변1

귀하의 질문이 다음과 동일하게 해석된다고 가정하면 Perl의 대안이 됩니다.sg-lecram의:

perl -lne 'tr{ }{}d;      # Remove whitespace in current line
           $lines{$_}++;  # Record the current line in a hash
           END{           # After all lines have been processed
               for(keys %lines){   # Iterate over hash keys
                 #Skip records with different letters:
                 next unless /([a-z]).*\1/i; 
                 ($first,$second)=split /,/; #Read the two fields
                 #Print the record unless its reciprocal is found:
                 print unless exists $lines{"$second,$first"}; 
           }' your_file

답변2

내가 아는 한, 다음 규칙은 원하는 결과를 생성합니다.

  • A1,A2: 같은 문자(예: "그룹") --> 찾기 A2,A1: 찾을 수 없음 --> 인쇄A2,A1
  • B1,B2: 같은 문자(예: "그룹") --> 찾기 B2,B1: 찾을 수 없음 --> 인쇄B2,B1
  • C1,C2: 같은 문자(예: "그룹") --> 검색 C2,C1: 찾기 --> 인쇄하지 않음
  • C2,C1: 같은 문자(예: "그룹") --> 검색 C1,C2: 찾기 --> 인쇄하지 않음
  • A1,C1: 다른 문자(예: "group") --> 인쇄하지 않음
  • A1,B1: 다른 문자(예: "group") --> 인쇄하지 않음
  • B1,A1: 다른 문자(예: "group") --> 인쇄하지 않음

따라서 목록에 하나가 있으면 A1,A3해당 항목도 인쇄되어야 합니다.

  • A1,A3: 같은 문자(예: "그룹") --> 찾기 A3,A1: 찾을 수 없음 --> 인쇄A3,A1

내 이해가 정확하다면 다음을 수행할 수 있습니다.

awk -F, '

  # skip records that do not consist of exactly two different fields
  (NF!=2)||($1==$2){
    next
  }

  # get groups
  {
     g1=substr($1,1,1) # If the groups are not defined as the first...
     g2=substr($2,1,1) # ...character, adjust theses line accordingly.
  }

  # only consider records with matching groups
  g1!=g2{
    next
  }

  # are we looking for the current record?
  ($2 in fst2scd)&&(fst2scd[$2]~FS""$1""FS){

    # remove "reciprocal" pair from the list (assuming record uniqueness -->...
    sub(FS""$1""FS,FS,fst2scd[$2]) # ...consider piping through sort -u first)

    # was that the last record ending with $2 we were looking for (so far)?
    if(fst2scd[$2]==FS){

      # remove $2 from the list (for now)
      delete fst2scd[$2]
    }

    # this "reciprocal" pair is done
    next
  }

  # if we reach this point, we found a new pair
  {

    # is this the first non-"reciprocal" record starting with $1?
    if(!($1 in fst2scd)){

      # add $1 to the list
      fst2scd[$1]=FS
    }

    # start looking for a "reciprocal" record
    fst2scd[$1]=fst2scd[$1]""$2""FS
  }

  # after processing all records, we know all non-"reciprocal" records
  END{

    # use the same separator for output that was used in input
    OFS=FS

    # iterate over all starts of records we are still looking for
    for(fst in fst2scd){

      # remove initial and final FS from list entry
      sub("^"FS,"",fst2scd[fst])
      sub(FS"$","",fst2scd[fst])

      # get all ends of records with the current start we are still looking for
      split(fst2scd[fst],scd,FS)

      # iterate over all the ends obtained in the previous step
      for(i in scd){

        # print the non-"reciprocal" records
        print fst,scd[i]
      }
    }
  }
' <<_INPUT_
A1,A2
B1,B2
C1,C2
C2,C1
A1,C1
A1,B1
B1,A1
A1,A3
A1,A1
_INPUT_

그러면 다음과 같은 출력이 생성됩니다.

A1,A2
A1,A3
B1,B2

FS항목에 포함될 수 있는 TSV 파일에서 동일한 코드가 실행될 수 있도록 스크립트 전체에서 사용에 유의하세요 ,.

이 코드의 작동 방식 및/또는 개선/조정 방법을 이해하는 데 추가 도움이 필요하면 언제든지 의견을 남겨주세요.

GNU awk또한 나는 당신이 이미 (즉, ) 실행 중이라고 가정합니다 gawk. 그렇지 않은 경우, Normal 에서 작동하도록 코드를 조정하는 데 도움을 드릴 수 있습니다 awk.

관련 정보