Nhờ tìm lỗi code không delete các dòng theo điều kiện

Liên hệ QC

AnhThu-1976

Thành viên tích cực
Tham gia
17/10/14
Bài viết
1,061
Được thích
175
Em chào các anh/ chị thành viên
Em có viết code như sau
Mã:
Sub Xoa()
Dim Lr As Long, i As Long
    Sheets("TH").Select
    Lr = ActiveSheet.Range("E" & Rows.Count).End(xlUp).Row
    
    For i = 9 To Lr
    If Cells(i, 5) = "Anh Thu" Then Cells(i, 5).EntireRow.Delete
    If Cells(i, 5) = "Anh Dung" Then Cells(i, 5).EntireRow.Delete
    If Cells(i, 5) = "Anh Hung" Then Cells(i, 5).EntireRow.Delete
    
    Next i

End Sub
Tại cột E của sheet TH, nếu ô nào có cụm từ Anh Thu hoặc Anh Dung hoặc Anh Hung thì delete dòng tương ứng, cho em hỏi 2 ý như sau

1/ Không biết code sai chổ nào, mà nó không delete hết các dòng theo điều kiện trên (đúng lý là nó delete các dòng tô chữ đỏ, nhưng nó delete không hết)

2/ Code trên duyệt từng ô từ dưới lên trên nên nó chạy chậm (nếu Data khoảng 5~ 7 ngàn dòng)

Nên anh/chị có code nào cho nó chạy nhanh hơn không thì giúp em
Em cảm ơn!
 

File đính kèm

  • XoaDong.xlsm
    15 KB · Đọc: 13
Nếu không thỏa mãn điều kiện thì trừ việc khai báo biến Rng As Range
thì Rng chưa được gán hay đả động gì cả thì sao mà Rng.EntireRow.Delete được.
Lúc này Rng rỗng mà, thì phải kiểm tra Rng 1 lần nữa, nếu nó không rỗng thì mới tiến hành xóa dòng.
Mã:
If Not Rng Is Nothing Then Rng.EntireRow.Delete
Để đoạn code này chỗ nào vậy bạn?
 
Upvote 0
Đúng là Code sẽ nhanh hơn cách thường tình là xóa từng dòng;
Nhưng với số dòng hàng vạn thì còn cách khác nhanh hơn:

Khai báo 1 biến mảng để chứa dữ liệu (DL)
B1.0: Xác định số dòng chứa DL (có dòng cần xóa)
B1.1 Khai báo thêm 1 mảng để chứa các dòng DL không cần xóa (Như aKQ() )
B2: Cho vùng DL này vô mảng để duyệt
B3: Tạo vòng lặp duyệt mảng DL;
Trong quá trình duyệt, dòng nào không thỏa điệu kiện xóa thì tăng biến đếm lên 1 & tiến hành ghi vô mảng aKQ()
B4: Sau khi duyệt xong ta kiểm tra
B4.1 Nếu mảng aKQ() có DL:
→ Xóa toàn bộ vùng DL;
→ Ghi DL từ mảng aKQ() lên trang tính;
B4.2 Nếu aKQ() là Nothing thì gởi lời chào tạm biệt!

Chúc bạn thành công nha, chủ bài đăng!
Cảm ơn anh @SA_DQ đã khai sáng.
Tôi hiểu thế này không biết có đúng không:
Vấn đề là số lượng dòng cần xóa với số lượng dòng cần giữ lại, cái nào nhiều hơn để quyết định phương án:
1/Nếu Số lượng dòng cần xóa ít hơn số lượng dòng cần gữi lại thì : Dùng Union gom những dòng cần Xóa và sau cùng là tiến hành xóa 1 lần.
2/ Nếu ngược lại thì : dùng 1 mảng để ghi lại những dòng không xóa. sau cùng xóa toàn bộ dữ liệu và gán mảng KQ vào sheet.
Tuy chưa bao giờ xác định trước số lượng bên nào nhiều hơn, nhưng quả thật là làm như phương án 2 thì tôi chưa bao giờ nghĩ đến, mà có dùng đén cũng chủ yếu là P.án1
 
Upvote 0
Duyệt trong mảng nhanh hơn là duyệt trên trang tính; Mình đọc được khẳng định này cũng trên diễn đàn này

Mình vừa mới nghĩ đến 1 cách nữa là áp dụng phương thức FIND()
Phương thức này chắc sẽ nhanh nếu số lượng dòng cần xóa là ít hay chưa có!
nhưng FIND() phải đi tìm 3 lần trong trường hợp cụ thể này.
Để mình tạo file giả lập thử thêm với phương án này so với phương án Union()
 
Upvote 0
Cảm ơn anh @SA_DQ đã khai sáng.
Tôi hiểu thế này không biết có đúng không:
Vấn đề là số lượng dòng cần xóa với số lượng dòng cần giữ lại, cái nào nhiều hơn để quyết định phương án:
1/Nếu Số lượng dòng cần xóa ít hơn số lượng dòng cần gữi lại thì : Dùng Union gom những dòng cần Xóa và sau cùng là tiến hành xóa 1 lần.
2/ Nếu ngược lại thì : dùng 1 mảng để ghi lại những dòng không xóa. sau cùng xóa toàn bộ dữ liệu và gán mảng KQ vào sheet.
Tuy chưa bao giờ xác định trước số lượng bên nào nhiều hơn, nhưng quả thật là làm như phương án 2 thì tôi chưa bao giờ nghĩ đến, mà có dùng đén cũng chủ yếu là P.án1
Hình như đơn giản ảnh chi tiết việc.
Nạp dữ liệu vào một mảng 2 chiều nạp dữ liệu từ sheet vào (thủ thuật tìm dòng cuối để nạp mảng);
Lập một mảng tạm gọi là kết quả aKQ, xong trong quá trình duyệt từ đầu đến cuối, nếu không thỏa điều kiện cần xóa, thì nạp trả vào mảng aKQ.
Hết vòng lặp thì xóa vùng dữ liệu trả lại xuống sheet thôi.
Ý ảnh ở đây là dùng mảng 2 chiều, tạm gọi là mảng nguồn, lọc kết quả loại thì thành mảng kết quả, đưa xuống sheet.
 
Upvote 0
& đây là kết quả so sánh giữa 2 cách:

Số dòng dữ liệu
12344​
Trong đó:Anh Khoa
441​
dòng
Anh Thu
1762​
dòng
Anh Dung
5292​
dòng
Union7 gy←Thời gian →chưa đến 1 gyĐưa vô mảng
 
Lần chỉnh sửa cuối:
Upvote 0
Độ dễ code:
1. đọc ngược, cần xóa dòng nào thì cứ thẳng tay tại chỗ.
2. đọc xuôi, cần xóa dòng nào thì ghi vào tập hợp (dùng từ khóa Union). Sau đó xóa một lần hết luôn.
3. chép qua mảng rồi duyệt, món nào cần lọc bỏ thì lướt qua, món nào còn giữ thì chép lại. Dùng 1 hay 2 mảng đều được. (Lưu ý: dân dùng mảng ở GPE này có thói quen dùng 2 mảng)

Độ nhanh của code:
- Ngược với độ dễ trên.

Nếu là tôi:
"tối ưu" là cách sử dụng tài nguyên.
- Mỗi ngày làm 1 lần thì cái nào cũng được
- Mỗi tuần làm 1 lần thì phương án 1 cho khỏe thân, dễ chỉnh sửa, debug.
- Vài ngày 1 lần thì có thể qua phương án 2, cũng dễ chỉnh sửa.
- Mỗi ngày làm vài lần thì mới dùng tới phương án 3.

Chú thích:
Code này
If Cells(i, 5) = "Anh Thu" Then Cells(i, 5).EntireRow.Delete
If Cells(i, 5) = "Anh Dung" Then Cells(i, 5).EntireRow.Delete
If Cells(i, 5) = "Anh Hung" Then Cells(i, 5).EntireRow.Delete
Không tương đương với code này
If Cells(i, 5) = "Anh Thu" Or Cells(i, 5) = "Anh Dung" Or Cells(i, 5) = "Anh Hung" Then Cells(i, 5).EntireRow.Delete
Cái trước là 3 lệnh, chạy xong lệnh này mới tiếp tục lệnh so sánh và thanh toán. Cái sau là soát cả 3 biểu thức, dùng toán tử Or để tính có thỏa hay khộng và sử lý mệnh đề đi theo.

Chú thích 2:
- Nếu con số điều kiện nhỏ thì dùng If-Or
- Nếu con số điều kiện nhiều hơn thì dùng Seelct Case dễ đọc và chỉnh sửa hơn (có thể nhanh hơn mọt chút, nhưng không đáng kể)
Select Cells(1, 5).Value
Case "Anh Thu", "Anh Hung", "Anh Dung"
...
- Nếu con số dưới 10 thì cho chúng vào một string rồi dùng hàm InStr
- Nếu con số dưới 20 thì cho chúng vào mảng rồi dùng hàm Match
- Nếu con số lớn thì dùng Dictionary
 
Upvote 0
[DÀNH CHO AI MUỐN THÊM 1 THAM KHẢO]

Mình có thêm cách xóa này nhanh hơn gần 3 lần so với phương thức xóa thông qua Union():

Mã:
Sub XoaFind()
 
 Sheets("TH").Select:               Tmr = Timer()
 XoaCon "Anh Thu"
 XoaCon "Anh Dung"
 XoaCon "Anh Khoa"
 [i99].End(xlUp).Offset(1).Value = Timer() - Tmr
End Sub
PHP:
Sub XoaCon(StrXoa As String)
 Dim Rng As Range, sRng As Range, dRg As Range
 Dim Rws As Long
 Dim MyAdd As String
 
 Rws = [B9].End(xlDown).Row
 Set Rng = [E8].Resize(Rws)
 Set dRg = Cells(Rws + 9, "E")
 Set sRng = Rng.Find(StrXoa, , xlFormulas, xlWhole)
 If Not sRng Is Nothing Then
    MyAdd = sRng.Address
    Do
        Set dRg = Union(dRg, sRng)
        Set sRng = Rng.FindNext(sRng)
    Loop While Not sRng Is Nothing And sRng.Address <> MyAdd
    [P20].End(xlUp).Offset(1).Value = dRg.Rows.Count
    dRg.EntireRow.Delete
 End If
End Sub
Tốn khoảng mươi gy so với 7 gy (nêu ở bài trên)
 
Lần chỉnh sửa cuối:
Upvote 0
Web KT

Bài viết mới nhất

Back
Top Bottom