loại bỏ trùng lặp dựa trên giá trị của cột khác


9

Tôi có tập tin sau:

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

Tôi đang cố gắng tìm kiếm các bản sao và loại bỏ dòng có giá trị cột bằng true.

như đầu ra nên là:

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

2
Vì vậy, .. chỉ giữ truenếu đó là phiên bản đầu tiên của cột đầu tiên?
DopeGhoti

1
@RomanPerekhrest Có lẽ vì là một mục uniq và được in "như hiện tại"
George Vasiliou

@RomanPerekhrest vì DD, đúng không phải là bản sao chúng tôi không có dòng khác với DD, sai.
Hani Gotc

AA,true AA,false AA,false AA,falseĐầu ra nào trong trường hợp này? Tôi hiểu, hàng đó chỉ nên được gỡ bỏ nếu nó có trùng lặp và chứa truecùng một lúc. Tất cả falsecác hàng nên được giữ nguyên trong mọi trường hợp. Đó là, trong trường hợp này, AA, truesẽ chỉ được gỡ bỏ. Nhưng tất cả các câu trả lời chỉ để lại một dòng - AA,false. Thật thú vị :)
MiniMax

Câu trả lời:


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

Để mở rộng tập lệnh theo chiều dọc để giải thích:

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 cũng giải thích! Bạn đã có +1 của tôi về điều này.
Valentin Bajrami

14

Phiên bản đơn giản:

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

"false" sắp xếp theo thứ tự abc trước "true" và lệnh Awk ở đây chỉ giữ hàng đầu tiên cho mỗi giá trị trường đầu tiên riêng biệt.

Nếu bạn muốn giữ "true" thay vì "false", hãy sắp xếp ngược lại, chuyển nó vào cùng một lệnh Awk và đảo ngược lại sắp xếp lại sau đó.


1
cũng có, nếu -utùy chọn có sẵn,sort input.txt | sort -t, -u -k1,1
Sundeep

2
@Sundeep tại sao sử dụng hai sortcuộc gọi? Tại sao không chỉ sort -ut, -k1,1 input.txt ?
terdon

2
@terdon vì -usẽ giữ lại dòng đầu tiên được tìm thấy từ tệp đầu vào trong số các bản sao ... đối với trường hợp cụ thể, đầu vào phải được sắp xếp trước khi -ucó thể được áp dụng ... ví dụ: AA,truesẽ được in thay vì AA,falsexuất hiện đầu tiên trong mẫu đã cho .. cùng một lý do tại sao awk -F, '!a[$1]++'một mình sẽ không giải quyết vấn đề này
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

Cấu trúc dữ liệu:

  • Hash %hcó khóa là các trường đầu tiên (AAA, BBB, CCC, v.v.) và các giá trị tương ứng là các số cho biết thứ tự mà các khóa gặp phải. Do đó, ví dụ: khóa AAA => 0, khóa BBB => 1, khóa CCC => 2.
  • Mảng @hcó các phần tử là các dòng chứa theo thứ tự in. Vì vậy, nếu cả hai đúng và sai được tìm thấy trong dữ liệu, thì giá trị sai sẽ đi vào mảng. OTW, nếu có một loại dữ liệu, thì nó sẽ xuất hiện.

Một cách khác là sử dụng 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, mã tương đương POSIX cho mã GNU-sed ở trên được liệt kê bên dưới:

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

Giải trình

  • Trong phương pháp này, chúng tôi lưu trữ kết quả cuối cùng sẽ được in trong không gian giữ.
  • Đối với mỗi dòng được đọc, chúng tôi sẽ thêm không gian giữ vào không gian mẫu để kiểm tra dòng hiện tại để xem trạng thái hiện tại của không gian giữ.
  • Bây giờ 5 điều có thể có thể xảy ra trong so sánh này:
    • a) Dòng hiện tại khớp với một nơi nào đó trong dòng giữ & false: false.
      • [HÀNH ĐỘNG] Vì cùng một trạng thái sai được tìm thấy, sau đó không làm gì cả.
    • b) Dòng hiện tại khớp với một nơi nào đó trong dòng giữ & true: true.
      • [HÀNH ĐỘNG] Vì cùng một trạng thái thực sự được tìm thấy, sau đó không làm gì cả.
    • c) Dòng hiện tại khớp với một nơi nào đó trong dòng giữ & true: false.
      • [HÀNH ĐỘNG] Vì một trạng thái sai đã tồn tại, không làm gì cả.
    • d) Dòng hiện tại khớp với một nơi nào đó trong dòng giữ & false: true.
      • [HÀNH ĐỘNG] Điều này liên quan đến một số công việc, trong đó chúng ta cần thay thế đường sai ở cùng một vị trí chính xác nơi đặt đúng.
    • e) Dòng hiện tại KHÔNG khớp với bất kỳ nơi nào trong dòng giữ.
      • [HÀNH ĐỘNG] Di chuyển dòng hiện tại đến cuối.

Các kết quả

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

3

Đối với mỗi dòng đầu vào, lưu trữ giá trị của trường thứ hai trong mảng kết hợp a(sử dụng trường thứ nhất làm khóa của mảng) CHỈ nếu chúng ta chưa lưu trữ giá trị falsecho khóa đó. Sử dụng ,cho cả dấu tách trường đầu vào và đầu ra. In ra mảng sau khi chúng tôi đọc tất cả các dòng đầu vào.

$ 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

Sự khác biệt đáng kể giữa phiên bản này và phiên bản DopeGhoti là phiên bản này hoàn toàn không quan tâm đến giá trị của $2nó, nó chỉ quan tâm đến giá trị, nếu có, của a[$1].


1

sortGiải pháp hai lượt

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

Đầu tiên sortvượt qua các bản ghi cụm theo trường 1với falsecác bản ghi trước truecho mỗi khối bản ghi chia sẻ một 1giá trị trường chung . sortVượt qua thứ hai được thiết lập để mang lại một bản ghi cho mỗi giá trị riêng biệt trong trường 1lịch sự -u. Kể từ -ungụ ý loại ổn định, một trong những kỷ lục do đó mang lại là kỷ lục đầu tiên gặp phải đối với từng giá trị riêng biệt trong lĩnh vực 1- đó là một kỷ lục với falsetrong lĩnh vực thứ hai do công việc được thực hiện bởi những người đầu tiên sortvượt qua

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.