Vòng lập for làm việc chậm

Liên hệ QC

lehoangcd09a

Thành viên mới
Tham gia
13/9/12
Bài viết
4
Được thích
0
Sub an_dong()
Dim i As Integer
For i = 77 To 33 Step -1
If Cells(i, 7) = 0 And Cells(i, 10) = 0 And Cells(i, 14) = 0 Then
Rows(i).Hidden = True
Else
Rows(i).Hidden = False
End If
Next
End Sub

Mình có viết một đoạn code như trên nhưng khi chạy thi đoạn code hoạt động khá lâu mới ẩn được các dòng có giá trị 0 nhờ các chuyên gia chỉnh sửa giúp em. Thanks mọi người
 
PHP:
Sub an_dong()
    Dim i As Long
    speed_on True
    With Sheet1 'cu the la sheet nao / Sheet1 là code name của worksheet '
        For i = 77 To 33 Step -1
            If .Cells(i, 7).Value2 = 0 Then 'OR: LEN(.Cells(i, 7).Value2) = 0 '
                If .Cells(i, 10).Value2 = 0 Then
                    If .Cells(i, 14).Value2 = 0 Then
                        .Rows(i).Hidden = True
                    Else
                        .Rows(i).Hidden = False
                    End If
                End If
            End If
        Next
    End With
    speed_on False
End Sub

Public Sub speed_on(ByVal bln As Boolean)
    With Application
        .ScreenUpdating = Not bln
        .DisplayAlerts = Not bln
        .Calculation = IIf(bln = True, xlCalculationManual, xlCalculationAutomatic)
    End With
End Sub
 
Upvote 0
PHP:
            If .Cells(i, 7).Value2 = 0 Then 'OR: LEN(.Cells(i, 7).Value2) = 0 '
                If .Cells(i, 10).Value2 = 0 Then
                    If .Cells(i, 14).Value2 = 0 Then
                        .Rows(i).Hidden = True
                    Else
                        .Rows(i).Hidden = False
                    End If
                End If
            End If
Cái code trên chưa chắc đã ra giống cái code của thớt nhé.
Code của thớt, trị hidden luôn luôn được đặt lại True hoặc False
Code của bạn, nếu không lọt qua 2 điều kiện đầu thì hidden được để đó.
 
Upvote 0
Chỉnh lại bài #2
Mã:
            If .Cells(i, 7).Value2 = 0 Then 'OR: LEN(.Cells(i, 7).Value2) = 0 '
                If .Cells(i, 10).Value2 = 0 Then
                    If .Cells(i, 14).Value2 = 0 Then
                        .Rows(i).Hidden = True
                    End If
                End If
            Else
                 .Rows(i).Hidden = False
            End If
 
Upvote 0
Hy vọng cái này giống code trên:

Mã:
Sub an_dong()
Dim i As Integer
Rows("33:77").Hidden = False
    For i = 77 To 33 Step -1
        If Cells(i, 7) = 0 Then
            If Cells(i, 10) = 0 Then
                If Cells(i, 14) = 0 Then
                    Rows(i).Hidden = True
                End If
            End If
        End If
    Next
End Sub
 
Upvote 0
Bạn thử phương pháp này coi sao:
Dùng giải thuật gán ghép về một range duy nhất rồi thực hiện Hidden, code bên dưới thay vì Hidden thì co giãn dòng.
Bạn thử với vài nghìn dòng xem sao.

Không nhất thiết phải Step là -1, bạn nên duyệt vòng lặp bình thường

PHP:
Sub SetHidden1()
  Dim I&, iHide&, nHide&, sRng$, sRng2$, iStep%
  iStep = -1 'Thủ tục này dành cho |iStep| = 1'
  With ThisWorkbook.Worksheets("Sheet1")
    For I = 77 To 33 Step iStep
      If .Cells(I, 7) = 0 And .Cells(I, 10)  = 0 And .Cells(I, 14) = 0 Then
        If iHide = 0 Then iHide = I
        GoSub Check2: nHide = 0
      Else
        If nHide = 0 Then nHide = I
        GoSub Check1: iHide = 0
      End If
    Next
    I = I + iStep: GoSub Check1: GoSub Check2
    If sRng <> "" Then .Range(sRng).EntireRow.RowHeight = 1
    If sRng2 <> "" Then .Range(sRng2).EntireRow.RowHeight = 15
  End With
Exit Sub
Check1:
  If iHide <> 0 Then sRng = sRng & IIf(sRng = "", "", ",") & "A" & iHide & ":A" & I - iStep
Return
Check2:
  If nHide <> 0 Then sRng2 = sRng2 & IIf(sRng2 = "", "", ",") & "A" & nHide & ":A" & I - iStep
Return
End Sub


Sub SetHidden2()
  Dim I&, iHide&, nHide&, sRng$, sRng2$, iStep%
  iStep = -1 'Thủ tục này dành cho |iStep| > 1'

  With ThisWorkbook.Worksheets("Sheet1")
    For I = 77 To 33 Step iStep
      If .Cells(I, 7) = 0 And .Cells(I, 10)  = 0 And .Cells(I, 14) = 0 Then
        sRng = sRng & IIf(sRng = "", "", ",") & "A" & I
      Else
        sRng2 = sRng2 & IIf(sRng2 = "", "", ",") & "A" & I
      End If
    Next
    If sRng <> "" Then .Range(sRng).EntireRow.RowHeight = 1 'Co vào'
    If sRng2 <> "" Then .Range(sRng2).EntireRow.RowHeight = 15 'Giãn ra'
  End With
Exit Sub

End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Mà mình hơi chút théc méc là chỉ có 40 dòng thôi sao lại chậm được nhỉ?
Đừng nói với tôi là gần ngàn cột đó nha!

Còn điều này nữa: Là tiến hành ẩn dòng chứ có phải xóa dòng đâu mà bạn bắt thêm Step -1 làm vậy?
 
Upvote 0
Hy vọng cái này giống code trên:

Mã:
Sub an_dong()
Dim i As Integer
Rows("33:77").Hidden = False
    For i = 77 To 33 Step -1
        If Cells(i, 7) = 0 Then
            If Cells(i, 10) = 0 Then
                If Cells(i, 14) = 0 Then
                    Rows(i).Hidden = True
                End If
            End If
        End If
    Next
End Sub
Làm như vầy luôn cho dễ đọc:
If (dieukien1) Then If (dieukien2) Then If (dieukien3) Then ....

Mà mình hơi chút théc méc là chỉ có 40 dòng thôi sao lại chậm được nhỉ?
Đừng nói với tôi là gần ngàn cột đó nha!

Còn điều này nữa: Là tiến hành ẩn dòng chứ có phải xóa dòng đâu mà bạn bắt thêm Step -1 làm vậy?
Nếu bảng tính có một đống hàm "volatile" thì mỗi lần hide/unhide dòng là chúng tính lại.
 
Upvote 0
Về mặt lý thuyết, ngôn ngữ lập trình thì:
Mã:
If A and B and C Then
    Do something
End If
sẽ tương đương với
Mã:
if A then
    if B then
        if C then
            Do something
        end if
    end if
end if
Tuy nhiên, về tốc độ thực thi thì khác nhau.
Cái dỡ của VB và VBA là thiếu tính năng Short logic như trong C/C++, Delphi, Java...
Nghĩa là trong trường hợp
Mã:
if A and B and C then
Nếu thực thi A trả về giá trị FALSE (0), thì các ngôn ngữ khác sẽ không thực thi và kiểm tra trị trả về của B và C, vì 0 and x and x luôn = 0
Nhưng VB/VBA thì luôn luôn thực thi và kiểm tra trị trả về của B và C, rồi mới tính kết quả cuối cùng của biểu thức A and B and C
Còn viết 3 if thì nếu A False thì 2 if sau không thực hiện
Vì vậy, viết if A and B and C thì thấy có vẽ ngắn hơn viết 3 if, nhưng tốc độ thực thi thì cuối cùng sẽ chậm hơn viết 3 if.
Các bạn chú ý điều này, viết ngắn chưa chắc đã tốt, tối ưu hay nhanh. Nên viết code rõ ràng, tường mình ra, dễ đọc, dễ bảo trì. Viết ngắn, nhiều code trên 1 hàng không được lợi gì đâu, đọc còn thấy rối nùi.
Vài lời "ngu ý" :)
PS: Cũng tương tự như if A or B, các bạn tìm hiểu thêm nhé.
 
Upvote 0
Thiệt ra thì nói về tốc độ không hẳn là đã hết câu chuyện.
Ở bài trên, tốc độ có thể hơi quan trọng một chút bởi vì thành phần so sánh có liên hệ đến hàm Value, lấy dữ liệu trực tiếp từ cell.
Nếu bài trên đã đổ dữ liệu ra mảng và đọc dữ liệu từ mảng thì tốc độ của "If (a and b and c)" và "if a then if b then if c" không chênh lệch nhau mấy.
Điểm quan trọng hơn mà các bạn cần để ý là khi các biểu thức bao gồm hàm.
Có 2 luật cần hiểu trong VBA:
1. Tất cả các trị trong biểu thức lômgic của IF đều được tính
2. Nếu có toán tử And thì biểu thức bên trái And được tính trước biểun thức bên phải
Ví dụ ta có 3 hàm f1(), f2(), f3() thì biểu thức If ( f1() And f3(), And f2() ) cần được hiểu rằng:
VBA sẽ chạy đủ 3 hàm f1, f2, f3 (theo luật 1) VÀ theo thứ tự trái qua phải (theo luật 2), tức là f1 tước, kế đó là f3, rồi đến f2 - lưu ý là ở biểu thức trên, f3 được sắp trước f2.

Các ngôn ngữ khác chưa hẳn đã vậy.
i) Một số ngôn ngữ không bảo đảm rằng biểu thức bên trái của And sẽ tính trước bên phải.
ii) Nhiều ngôn ngữ về sau này sẽ dùng luật tính lô gic đường tắt (short-circuit evaluation). Tức là nó sẽ tự biết lúc để ngưng không cần tính hết chỗ còn lại.
Ví dụ If ( f1() And f3() And f2() ) mà trong đó f1 đã false rồi thì nó tự biết khong cần tính tiếp (đối với And, chỉ cần 1 false thì kết quả cuối cùng là false)
 
Upvote 0
.
 
Lần chỉnh sửa cuối:
Upvote 0
Mã:
a+b+c=0
Thì đâu nhất thiết a=0, b=0, c=0..
 
Upvote 0
...
Thử đơn giản hóa dựa trên bài viết #1

If .Cells(I, 7) + .Cells(I, 10) + .Cells(I, 14) = 0 Then
...
Cái này thì không phải là đơn giản mà là lô gic khác hoàn toàn. Nếu chúng không phải là 0 nhưng lại triệt nhau thì sao? ( 1 + 0 + -1)

...
VB và VBA là Script nhúng trong ứng dụng, không phải ngôn ngữ lập trình.
VBA chỉ sử dụng một luồng duy nhất nên cấu trúc trong một câu lệnh sẽ được dịch toàn bộ.
Nếu bạn nói thiếu Short logic là "Cái dỡ", còn nếu có Short logic thì nó sẽ phá hỏng một cơ chế đơn luồng
Kết cục bạn không thể viết code VBA cho một cell Excel, sẽ không biết hàm nào sẽ kết thúc trả kết quả trước (Super Bad).
...
Dịch là một chuyện, vận hành là chuyện khác. Cái chuyện "đi tắt" chỉ là tiêu chuẩn riêng của mỗi ngôn ngữ thôi.
JavaScript cũng dùng phép dịch từng câu. Nhưng ngôn ngữ này lại theo luật "đi tắt".

Ở trên tôi có nói "những ngôn ngữ về sau này..."
VBA dựa trên BASIC, là ngôn ngữ khá cổ điển cho nên nó không theo trào lưu về sau này. Tức là luật đi tắt. Giản dị vậy thôi.
 
Upvote 0
Bạn HeSanbi cứ thích đao to búa lớn, dùng dao mổ trâu giết gà kg, hì hì
If a + b + c = 0 về logic đã sai, mà tốc độ cũng chậm hơn 3 if: if a then if b then if c then, vì trình thông dịch của VBA trong VBEx.dll phải tính cả 3 giá trị a, b, và c rồi phải cộng, rồi so sánh = 0
Vòng lặp for nhỏ, data nhỏ thì thấy kg sao, nhưng ngược lại hay test trên máy chậm thì thấy mữa mật ngay
 
Upvote 0
.
 
Lần chỉnh sửa cuối:
Upvote 0
Chi cho khổ, vẽ cực ra làm chi vậy bạn. Bạn code (A = B) + C = 0 thì chỉ mình bạn hiểu, người khác đọc code bạn khó hiểu, thậm chí sau này chính bạn đọc lại còn kg hiểu mình viết gì.
Nếu cả 3 A, B, C đều =0, thì code bạn lại sai nữa.
(0 = 0) + 0 = True + 0 = True khác 0
Hoặc A = 1, B = 0, C = 0
(A = B) + C =(1 = 0) + 0 = 0 + 0 = 0 (nhưng A = 1 <> 0)
 
Lần chỉnh sửa cuối:
Upvote 0
.
 
Lần chỉnh sửa cuối:
Upvote 0
Hì hì,lại sai nữa, suy nghĩ kỹ chưa, nếu A = B = C = 0 thì sao ? ;)
 
Lần chỉnh sửa cuối:
Upvote 0
Bạn thông cảm nhé, hai ngày nay tôi mất ngủ, và thực là tư duy không còn chút logic, các bài viết sẽ được ".". Tác hại này đến từ việc ngồi pc quá 16 tiếng 1 ngày. Tôi cảm giác não bộ không còn như tôi muốn.
 
Lần chỉnh sửa cuối:
Upvote 0
Web KT

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

Back
Top Bottom