別の列の値に基づいて重複を削除する


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 2017

1
@RomanPerekhrestおそらくuniqエントリであり、「
現状のまま

@RomanPerekhrest DD、trueは重複ではないため、DD、falseの別の行はありません。
ハニGotc 2017

AA,true AA,false AA,false AA,falseこの場合、どのような出力になりますか?行が重複していtrueて、同時に含まれている場合にのみ、その行を削除する必要があることを理解しています。falseいずれの場合も、すべての行は変更しないでください。つまり、この場合のみAA, true削除されます。しかし、すべての答えは1行しか残しません- AA,false。ただ面白い:)
MiniMax 2017

回答:


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を持っています。
Valentin Bajrami 2017

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なぜ2つのsort呼び出しを使用するのですか?なぜsort -ut, -k1,1 input.txt ですか?
terdon

2
@terdon -uは重複する入力ファイルから見つかった最初の行を保持するため、特定のケースでは、入力を-u適用する前に入力をソートする必要があります... ex:の場合AA,trueAA,false、指定されたサンプルの最初に表示されるため、代わりに出力されます。それawk -F, '!a[$1]++'だけではこの問題が解決されないのと同じ理由
サンディープ2017

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、1つのタイプのデータがある場合、それは存在します。

別の方法は、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

FWIW、上記のGNU sedコードに対応する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。
      • [アクション]これには、trueが配置されているのとまったく同じ位置でfalseの行を置き換える必要があるという点で、いくつかの作業が含まれます。
    • e)現在の行は保留行のどこにも一致しません。
      • [アクション]現在の行を最後に移動します。

結果

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

3

各入力ラインのために、連想配列の2番目のフィールドの値を格納するa(配列のキーように、第1のフィールドを使用して)ONLYすでに値が格納されていない場合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値。2番目のsortパスは1、フィールドの厚意により、各値ごとに1つのレコードを生成するように設定されてい-uます。-u安定したソートを意味するため、このように生成された1つのレコードは、フィールド内の各個別の値に遭遇した最初のレコードです。1これはfalse、最初のsortパスで行われた作業により2番目のフィールドにあるレコード

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.