hapus duplikat berdasarkan nilai kolom lain

9

Saya memiliki file berikut:

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

Saya mencoba mencari duplikat dan menghapus baris yang memiliki nilai kolom sama dengan true.

sebagai output seharusnya:

AA,false
BB,false
CC,false
DD,true
Hani Gotc
sumber
2
Jadi .. hanya simpan truejika itu contoh pertama dari kolom pertama?
DopeGhoti
1
@RomanPerekhrest Mungkin karena merupakan entri unik dan dicetak "sebagaimana adanya"
George Vasiliou
@RomanPerekhrest karena DD, true bukan duplikat kami tidak memiliki baris lain dengan DD, false.
Hani Gotc
AA,true AA,false AA,false AA,falseOutput apa yang harus dalam kasus ini? Saya mengerti, baris itu harus dihapus hanya jika memiliki duplikat dan mengandung truepada saat yang sama. Semua falsebaris harus tetap tidak tersentuh dalam hal apa pun. Artinya, dalam hal ini, hanya AA, trueakan dihapus. Tetapi semua jawaban hanya menyisakan satu baris - AA,false. Cukup menarik :)
MiniMax

Jawaban:

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

Untuk memperluas skrip secara vertikal untuk penjelasan:

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
sumber
@DopeGhoti menjelaskan dengan baik! Anda mendapatkan +1 saya untuk ini.
Valentin Bajrami
14

Versi sederhana:

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

"false" mengurutkan secara alfabet sebelum "true," dan perintah Awk di sini hanya membuat baris pertama hanya untuk setiap nilai bidang pertama yang berbeda.

Jika Anda ingin tetap "benar", bukan "salah," balikkan urutkan, berikan ke perintah Awk yang sama, dan balikkan urutkan lagi sesudahnya.

Wildcard
sumber
1
juga, jika -uopsi tersedia,sort input.txt | sort -t, -u -k1,1
Sundeep
2
@ Simpan mengapa menggunakan dua sortpanggilan? Kenapa tidak adil sort -ut, -k1,1 input.txt ?
terdon
2
@terdon karena -uakan mempertahankan baris pertama yang ditemukan dari file input di antara duplikat ... untuk kasus yang diberikan, input harus disortir sebelum -udapat diterapkan ... misalnya: AA,trueakan dicetak alih-alih AA,falsekarena muncul pertama kali dalam sampel yang diberikan .. alasan yang sama mengapa awk -F, '!a[$1]++'sendirian tidak akan menyelesaikan masalah ini
Sundeep
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

Struktur data:

  • Hash %hyang kuncinya adalah bidang pertama (AAA, BBB, CCC, dll.) Dan nilai yang sesuai adalah angka yang memberi tahu urutan kemunculan kunci tersebut. Jadi, misalnya, kunci AAA => 0, kunci BBB => 1, kunci CCC => 2.
  • Array @hyang elemen-elemennya adalah garis-garis yang terdapat dalam urutan pencetakan. Jadi jika benar dan salah ditemukan dalam data, maka nilai palsu akan masuk ke array. OTW, jika ada satu jenis data, maka itu akan hadir.

Cara lain menggunakan sed GNU:

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, kode setara POSIX untuk kode sed GNU di atas tercantum di bawah ini:

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

Penjelasan

  • Dalam metode ini kami menyimpan hasilnya untuk akhirnya dicetak di ruang penahanan.
  • Untuk setiap baris yang dibaca, kami menambahkan ruang pegang ke ruang pola untuk pemeriksaan garis saat ini berhadapan dengan keadaan ruang pegang yang ada.
  • Sekarang 5 hal yang mungkin terjadi selama perbandingan ini:
    • a) Baris saat ini cocok dengan suatu tempat di baris tahan & false: false.
      • [AKSI] Karena keadaan salah yang sama ditemukan, maka jangan lakukan apa pun.
    • b) Baris saat ini cocok dengan suatu tempat di baris terus & true: true.
      • [AKSI] Karena keadaan sebenarnya yang sama ditemukan, maka jangan lakukan apa pun.
    • c) Baris saat ini cocok dengan suatu tempat di baris tahan & true: false.
      • [AKSI] Karena keadaan palsu sudah ada, jangan lakukan apa pun.
    • d) Baris saat ini cocok di suatu tempat di baris tahan & false: true.
      • [AKSI] Ini melibatkan beberapa pekerjaan, di mana kita perlu mengganti garis palsu pada posisi yang sama persis di mana yang benar berada.
    • e) Baris saat ini TIDAK cocok dengan di mana pun di baris terus.
      • [AKSI] Pindahkan garis sekarang ke ujung.

Hasil

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

sumber
3

Untuk setiap baris input, simpan nilai bidang kedua dalam array asosiatif a(menggunakan bidang pertama sebagai kunci array) HANYA jika kami belum menyimpan nilai falseuntuk kunci tersebut. Gunakan ,untuk pemisah bidang input dan output. Cetak array setelah kita membaca semua jalur input.

$ 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

Perbedaan signifikan antara ini dan versi DopeGhoti adalah bahwa versi ini tidak peduli sama sekali tentang nilai $2, hanya peduli tentang nilai, jika ada, dari a[$1].

cas
sumber
1

sortSolusi dua jalur

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

sortCatatan kelompok pertama lulus oleh lapangan 1dengan falsecatatan sebelumnya trueuntuk setiap blok catatan berbagi 1nilai bidang umum . Kedua sortlulus diatur untuk menghasilkan satu catatan untuk setiap nilai yang berbeda dalam bidang 1sopan santun -u. Karena -umenyiratkan jenis yang stabil, maka satu catatan yang dihasilkan adalah rekaman pertama yang ditemukan untuk setiap nilai berbeda dalam bidang 1- yang merupakan catatan dengan falsedi bidang kedua karena pekerjaan yang dilakukan oleh sortlintasan pertama

iruvar
sumber