共通記録確認

共通記録確認

いくつかの履歴をすばやく確認するために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:他の文字(例:「グループ」) - >印刷しない
  • A1,B1:他の文字(例:「グループ」) - >印刷しない
  • B1,A1:他の文字(例:「グループ」) - >印刷しない

したがって、リストに1つがある場合は、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

関連情報