Chuyên mục xử lý, gỡ rối code VBA (2 người xem)

Liên hệ QC

Người dùng đang xem chủ đề này

Status
Không mở trả lời sau này.

ndu96081631

Huyền thoại GPE
Thành viên BQT
Super Moderator
Tham gia
5/6/08
Bài viết
30,703
Được thích
53,957
Hình như Nghĩa viết xong rồi chưa chạy thử thì phải code bài 377 và bài này mình chạy thử cả hai thấy báo lỗi...
Sorry, tôi viết mà không thử, bạn sửa lại chỗ này:

LastRow = .Range("C" & MaxRow).End(xlUp)

Thành:

LastRow = .Range("C" & MaxRow).End(xlUp).Row

Mã:
Sub LocDuyNhat()
    Dim LastRow As Long, MaxRow As Long
    ''Tinh so hang lon nhat:
    MaxRow = Rows.Count
    With ActiveSheet ''<-- Co the thay bang ten sheet khac
        ''Loai bo AutoFilter:
        .AutoFilterMode = False
       ''Tim hang cuoi:
        LastRow = .Range("C" & MaxRow).End(xlUp)[COLOR=#ff0000][B].Row[/B][/COLOR]
       ''Neu hang cuoi nho hon hang tieu de thi thoat
        If LastRow < 4 Then Exit Sub
        Dim Nguon, KQ
        Dim i As Long, k As Long
        Dim Tmp1 As String, Tmp2 As String
        Nguon = .Range("C4:D" & LastRow)
        ReDim KQ(1 To MaxRow, 1 To 2)
        With CreateObject("Scripting.Dictionary")
            For i = 1 To UBound(Nguon)
                Tmp1 = CStr(Nguon(i, 1))
                Tmp2 = CStr(Nguon(i, 2))
               ''Ca 2 phai khac rong moi chap nhan:
                If Tmp1 > "" And [B][COLOR=#ff0000]Tmp2 [/COLOR][/B]> "" Then
                    If Not .Exists(Tmp1) Then
                        .Add Tmp1, Empty
                        k = k + 1
                        KQ(k, 1) = Tmp1
                        KQ(k, 2) = Tmp2
                    End If
                End If
            Next i
        End With
        .Range("G4:H" & MaxRow).ClearContents
        If k Then .Range("G4").Resize(k, 2) = KQ
    End With
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
... trước khi End Sub, một lần nữa nó giải phóng cái biến mảng đó cũng ngốn đi một khoảng thời gian nữa. ...

Từ hồi tôi biết VBA tới giờ, tôi chỉ đoán mò là nó giải phóng mảng bằng cách tương tự như Java, tức là biến chỉ cần ra khỏi phạm vi (exit sub) thì vùng nhớ tự nhiên được nhả ra, và cổ máy gom rác (garbage collection) tự động gom nó trả về cho heap.
Có lẽ trên thực tế, VBA sử dụng bộ nhớ theo cách khác?
 
Upvote 0
Từ hồi tôi biết VBA tới giờ, tôi chỉ đoán mò là nó giải phóng mảng bằng cách tương tự như Java, tức là biến chỉ cần ra khỏi phạm vi (exit sub) thì vùng nhớ tự nhiên được nhả ra, và cổ máy gom rác (garbage collection) tự động gom nó trả về cho heap.
Có lẽ trên thực tế, VBA sử dụng bộ nhớ theo cách khác?
Anh cũng có thể tự làm thí nghiệm mà. Khi kết thúc với End hay Exit Sub/ Function thì mọi biến sẽ được giải phóng, trừ các biến đặt ở ngoài Sub/ Function hoặc các biến là đối số được khai báo bởi ByRef hoặc biến được khai bởi Static.
 
Lần chỉnh sửa cuối:
Upvote 0
Theo lý thuyết lập trình, khi biến ra khỏi phạm vi (chấm dứt vùng tầm vực, theo ngôn ngữ của Trần Thanh Phong, trong bài nói về biến) thì biến coi như được xoá sổ.

Theo kiến thức của tôi về VBA thì đó là chấm dứt nhiệm vụ của chương trình đối với vùng nhớ mà VBA giành cho biến. Việc đem vùng nhớ trả về cho vùng nhớ chung (heap memory) là công việc của cổ máy garbage collection. Cũng theo kiến thức giới hạn của tôi thì cỏ máy này khá đơn giản, chỉ làm việc bằng cách đếm references. Khi biến không sử dụng vùng nhớ nữa thì nó trừ reference đi 1. Khi số references về đến ze rô thì garbage collection coi như vùng nhớ hiện không thuộc về biến nào cả và có thể gom được. Như vậy việc biến nhả vùng nhớ chỉ xảy ra trong vòng vài lệnh máy - tức là vài phần tỷ giây. Không xứng đáng phải quan tâm. Chỉ có công việc lấy vùng nhớ cho mảng (memory allocation) mới phức tạp hơn một chút. Nhưng cũng rất nhanh, kỹ thuật này được viết bằng các hàm macro máy (assembly macro) nên rất hiệu quả.
 
Upvote 0
Theo lý thuyết lập trình, khi biến ra khỏi phạm vi (chấm dứt vùng tầm vực, theo ngôn ngữ của Trần Thanh Phong, trong bài nói về biến) thì biến coi như được xoá sổ.

Theo kiến thức của tôi về VBA thì đó là chấm dứt nhiệm vụ của chương trình đối với vùng nhớ mà VBA giành cho biến. Việc đem vùng nhớ trả về cho vùng nhớ chung (heap memory) là công việc của cổ máy garbage collection. Cũng theo kiến thức giới hạn của tôi thì cỏ máy này khá đơn giản, chỉ làm việc bằng cách đếm references. Khi biến không sử dụng vùng nhớ nữa thì nó trừ reference đi 1. Khi số references về đến ze rô thì garbage collection coi như vùng nhớ hiện không thuộc về biến nào cả và có thể gom được. Như vậy việc biến nhả vùng nhớ chỉ xảy ra trong vòng vài lệnh máy - tức là vài phần tỷ giây. Không xứng đáng phải quan tâm. Chỉ có công việc lấy vùng nhớ cho mảng (memory allocation) mới phức tạp hơn một chút. Nhưng cũng rất nhanh, kỹ thuật này được viết bằng các hàm macro máy (assembly macro) nên rất hiệu quả.

Em thì chả có học cao siêu gì, nhưng nếu thí nghiệm trên một sheet mà dữ liệu đủ lớn để thấy được thời gian nhận biến và giải phóng biến thì dùng code này sẽ thấy có một sự chênh lệch về thời gian, do đâu? Phải chăng là thời gian nó giải phóng biến?

Mã:
Option Explicit
Dim T As Double


Sub TestTime1()
    T = Timer
    Dim Arr()
    Arr = Sheet1.UsedRange.Value
    Debug.Print Timer - T
End Sub


Sub TestTime2()
    TestTime1
    Debug.Print Timer - T
End Sub
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Test Timer như vậy chưa hẳn đã chính xác. Theo nguyên tắc tính thời gian, nguoiwf ta cho code chạy khoảng vài trăm vòng và lập biểu đồ thống kê kết quả. Nói chung thì cuối cùng code sẽ có một điểm bảo hoà.

Tuy nhiên, để diễn tả cho bạn thấy rằng timer không chính xác để đo tốc độ chạy của code. Tôi thử code sau:

Function ftt() As Single
Dim Arr()
Arr = Sheet1.UsedRange.Value
ftt = Timer
End Function

Sub stt()
Dim i As Integer
For i = 1 To 100: Debug.Print ftt - Timer; Timer - ftt: Next i
End Sub

Theo lý thuyết thì kết quả ở mỗi dòng in ra, trị thứ nhất và trị thứ hai phải gần giống nhau. Trên thực tế thì khác hẳn.

(*) timer là single chứ không phải double. Nhưng cái này không quan trọng.
 
Upvote 0
Mã:
Option Explicit
Dim T As Double


Sub TestTime1()
    T = Timer
    Dim Arr()
    Arr = Sheet1.UsedRange.Value
    Debug.Print Timer - T
End Sub


Sub TestTime2()
    TestTime1
    Debug.Print Timer - T
End Sub

Theo hiểu biết ít ỏi của tôi thì mọi tiến trình hay lệnh được xử lý trong máy tính đều tốn thời gian cả dù thời gian này có khi nhỏ hơn cả 1 mili giây (micro giây). Bởi thế có hay không có giải phóng bộ nhớ thì chỉ mỗi lệnh gán Arr = Sheet1.UsedRange.Value cũng đã tốn 1 khoảng thời gian (dù cực nhỏ).

Ở đây thấy có người đề cập tới Heap, stack.... trong bộ nhớ, những lý thuyết được khá nhiều giáo trình minh họa bằng các vị dú viết bằng ngôn ngữ cấp cao như Pascal, VB... để giúp người đọc có thể hiểu. Tuy nhiên đây chỉ là minh họa. Nếu chúng ta hiểu như thế thì không khác nào những đứa trẻ cứ ngộ rằng các hạt vật chất có dạng hình cầu xanh đỏ như trong hình vẽ minh họa SGK trong khi thực tế chẳng ai biết các hạt đấy hình thù màu sắc thế nào...

Các khái niệm về heap, stack... trong bộ nhớ là những khái niệm khá trừu tượng hay gặp phải khi lập trình các ngôn ngữ cấp thấp như asm, C/C++. Và chúng là những khái niệm làm đau đầu những người viết code thưở xa xưa. Các ngôn ngữ cấp cao sau này điển hình như VB được thiết kế với một trong những mục tiêu là làm sao cho người viết code được quẳng bỏ những lo toan về quản lý bộ nhớ này nọ để dành tâm chí cho các giải thuật thiết thực.

Trừ khi bạn cố gắng quay trở về những heap, stack... của bộ nhớ với các APi thao tác trực tiếp, còn thức tế thì những lý thuyết này không hiện diện trong bất cứ đoạn code nào bạn viết cả, có chăng là nó ẩn sâu trong các mã máy được biên dịch sau cùng và chúng cũng nằm ngoài ý chí chủ quan của bạn.
 
Upvote 0
Em muốn đặt biến m, n là số hàng và số cột của Cell trong excel. Khi dùng Cells(m,n) = xyz thì được nhưng khi dùng với công thức theo kiểu R1C1 thì báo lỗi 1004 "Application defined or object defined". Code em viết thế này:
Dim m, n, sothutu As Long
sothutu = FilterDate.Cells(3, 4)
cotmot = sothutu * 2
cothai = cotmot - 1


Sheets("FilterDate").Select
Range("A6").Select
ActiveCell.FormulaR1C1 = _
"=IF(Ex_Date!R[1]C[cotmot]=FilterDate!R2C3,Ex_Date!R[1]C[1],"""")"
Range("B6").Select
ActiveCell.FormulaR1C1 = _
"=IF(Ex_Date!R[1]C[cothai]=FilterDate!R2C3,Ex_Date!R[1]C[cotmot],"""")"
Em mới học mong các bác chỉ cách dùng đúng ạ
 
Upvote 0
... để dành tâm chí cho các giải thuật thiết thực.
...

Định nghĩa thế nào là giải thuật thiết thực?

Ở đây trình độ hầu hết chỉ tới mức sao chép chuyển đổi tom góp dữ liệu. Đâu có ai đạt đến mức đồ án dự án hằng trăm modules, hằng ngàn dòng code như bạn đâu mà cần phải mô hình này nọ.
 
Upvote 0
Định nghĩa thế nào là giải thuật thiết thực?

Ở đây trình độ hầu hết chỉ tới mức sao chép chuyển đổi tom góp dữ liệu. Đâu có ai đạt đến mức đồ án dự án hằng trăm modules, hằng ngàn dòng code như bạn đâu mà cần phải mô hình này nọ.
Tôi thì không phải người giỏi chữ nghĩa nên chắc dùng từ ngữ ngô ngê chăng? Nếu có gì sai thì vui lòng chỉ bảo.

Hình như trí tuệ của bạn có khả năng hư cấu, thêm thắt và phóng tác thì phải. Chẳng biết lấy dữ kiện đâu ra mà bạn bỗng chốc biến tôi từ một kẻ Vô danh Tiểu tốt mở miệng bằng câu "Theo hiểu biết ít ỏi của tôi" bỗng thành một siêu nhân.

Rất cám ơn bạn vì đã dành cho Vô danh Tiểu tốt tôi những mỹ từ hoàng tráng đó nhưng tôi xin trả lại bạn vì có vẻ là bạn xứng đáng hơn.
 
Lần chỉnh sửa cuối:
Upvote 0
xin chỉ giúp cải thiện tốc đoạn code sau!

Xin các anh chị chỉ giúp em cách cải thiện tốc độ của đoạn code sau: nếu lặp khoảng 10.000 lần.
Private Sub Check_Click()
Dim i, j As Integer
For i = 1 To 10
For j = i + 1 To 10
If (Cells(i, 2) = Cells(j, 2) And Cells(i, 3) = Cells(j, 3) And Cells(i, 4) = Cells(j, 4)) Then
Cells(i, 2).Select
With Selection.Font
.Color = -16776961
.TintAndShade = 0
End With
Cells(i, 3).Select
With Selection.Font
.Color = -16776961
.TintAndShade = 0
End With
Cells(i, 4).Select
With Selection.Font
.Color = -16776961
.TintAndShade = 0
End With
Cells(j, 2).Select
With Selection.Font
.Color = -16776961
.TintAndShade = 0
End With
Cells(j, 3).Select
With Selection.Font
.Color = -16776961
.TintAndShade = 0
End With
Cells(j, 4).Select
With Selection.Font
.Color = -16776961
.TintAndShade = 0
End With
End If
Next j
Next i
End Sub
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Mình không có Excel 2007 để thử property TintAndShade nên mình chỉ đóng góp thế này: bạn đang định dò bảng, nếu có 2 dòng i, j mà các ô cột B, C, D trùng nhau thì sẽ tô màu đỏ các ô này. Theo chương trình bạn làm thì giả sử dòng 1, 2, 3, 4 trùng nhau thì mỗi dòng sẽ tô màu đỏ lặp lại 3 lần làm giảm thời gian. Theo mình, bạn nên insert 1 cột E trống, gán bảng B1:E1000 vào mảng arr(1 to 1000, 1 to 4) sau đó lặp như sau
Mã:
Application.ScreenUpdating=False
For i = 1 to 999
   'nếu arr(i,4)=TRUE tức là hàng i đã tô màu thì next i
   if not arr(i,4) then  
     for j=i+1 to 1000
     'nếu arr(j,4)=TRUE tức là hàng j đã tô màu thì next j  
         if not arr(j,4) and arr(i,1)=arr(j,1) and arr(i,2)=arr(j,2) and arr(i,3)=arr(j,3) then
              if not arr(i,4) then
               'kiểm tra lại xem hàng i đã tô màu trong lần lặp với các giá trị j trước chưa   
                  arr(i,4)=TRUE
                  Range("B" & i, "D" & i).Font.Color=-16776961
                  Range("B" & i, "D" & i).Font.Tintandshade=0
              end if
              arr(j,4)=TRUE
              Range("B" & j, "D" & j).Font.Color=-16776961
              Range("B" & j, "D" & j).Font.Tintandshade=0
         end if
      next j
   end if
next i
Columns(5).delete
Application.ScreenUpdating=True
 
Upvote 0
Các bạn cho tôi hỏi:
Tôi có đọan code đặt trong sheet
Mã:
Private Sub Worksheet_Change(ByVal Target As Range)  Dim rCel As Range, rFind As Range, rSrc As Range, rTarget As Range
  On Error GoTo ExitSub
  If Not Intersect(Range(
 
Lần chỉnh sửa cuối:
Upvote 0
Các bạn giải thích giùm tại sao cái dòng màu đỏ nó kg có tác dụng vậy?
Hoặc các bạn có cách khác nào để mỗi khi chạy code thì File tự động chuyển sang Manual, dù trước đó người dùng đã chuyển sang chế độ Automatic
Cãm ơn các bạn!
Chắc không phải tại dòng code không có tác dụng mà là code bị gì gì đó nên nó chạy tuốt xuống Exit Sub luôn rồi. Mà mình đọc sơ qua code thấy vướng vướng sao ấy.
Kinh nghiệm cho thấy bài hỏi có kèm file thường nhận đáp án nhanh và chính xác.
 
Upvote 0
Chắc không phải tại dòng code không có tác dụng mà là code bị gì gì đó nên nó chạy tuốt xuống Exit Sub luôn rồi. Mà mình đọc sơ qua code thấy vướng vướng sao ấy.
Kinh nghiệm cho thấy bài hỏi có kèm file thường nhận đáp án nhanh và chính xác.
Cảm ơn bạn đã giúp
Tôi đã kiểm tra lại, nếu chỉ mở 1 file chưa code trên thì dù ở chế độ nào nó vẫn chạy tốt
Chỉ khi nào mở nhiều file có những đọan code khác, hoặc chương trình khác thì mới bị lỗi trên
Code trên là tôi sưu tầm trên GPE, code này là của người siêu về code
Bạn có thể tìm nó ở dưới đường Link sau
http://www.giaiphapexcel.com/forum/...ter-thì-Cell-C10-hiện-tên-hàng-hóa-tương-ứng!
 
Lần chỉnh sửa cuối:
Upvote 0
Cảm ơn bạn đã giúp
Tôi đã kiểm tra lại, nếu chỉ mở 1 file chưa code trên thì dù ở chế độ nào nó vẫn chạy tốt
Chỉ khi nào mở nhiều file có những đọan code khác, hoặc chương trình khác thì mới bị lỗi trên
Code trên là tôi sưu tầm trên GPE, code này là của người siêu về code
Bạn có thể tìm nó ở dưới đường Link sau
http://www.giaiphapexcel.com/forum/...ter-thì-Cell-C10-hiện-tên-hàng-hóa-tương-ứng!

Code không vấn đề gì, vướng vướng là vì không có file sao biết code có suông sẻ hay không. Code phải phù hợp với từng loại dữ liệu chứ. Cho nên phải có file thôi.
 
Upvote 0
nhờ các bạn giải thích code giúp mình

Mã:
[COLOR=#000000]Dim strCom As String
Dim objWMIService As Object[/COLOR]
[COLOR=#000000]Dim colAdapters As Object[/COLOR]
[COLOR=#000000]Dim objAdapter As Object[/COLOR]
[COLOR=#000000]strCom = "."[/COLOR]
[COLOR=#000000]Set objWMIService = GetObject _[/COLOR]
[COLOR=#000000]("winmgmts:" & "!\\" & strCom & "\root\cimv2")[/COLOR]
[COLOR=#000000]Set colAdapters = objWMIService.ExecQuery _[/COLOR]
[COLOR=#000000]("Select * from Win32_NetworkAdapterConfiguration Where IPEnabled = True")[/COLOR]
[COLOR=#000000]For Each objAdapter In colAdapters[/COLOR]
[COLOR=#000000]Sheets("login").Range("AB25") = objAdapter.MACAddress[/COLOR]
[COLOR=#000000][INDENT]Next objAdapter[/INDENT]
[/COLOR]


công dụng cuối cùng của nó là gán địa chỉ MAC của máy tính cho ô AB25 để dùng những thuật toán mã hóa tạo CDkey nhưng tại sao lại tạo truy vấn và duyệt vòng lập trong đó
Nhân tiện các bạn biết kiểu biến Object có tác dụng gì không ạ, và khi nào mới sử dụng nó, cám ơn các bạn đã đọc bài viết​
 
Lần chỉnh sửa cuối:
Upvote 0
nhờ các bạn giải thích code giúp mình

Mã:
[COLOR=#000000]Dim strCom As String
Dim objWMIService As Object[/COLOR]
[COLOR=#000000]Dim colAdapters As Object[/COLOR]
[COLOR=#000000]Dim objAdapter As Object[/COLOR]
[COLOR=#000000]strCom = "."[/COLOR]
[COLOR=#000000]Set objWMIService = GetObject _[/COLOR]
[COLOR=#000000]("winmgmts:" & "!\\" & strCom & "\root\cimv2")[/COLOR]
[COLOR=#000000]Set colAdapters = objWMIService.ExecQuery _[/COLOR]
[COLOR=#000000]("Select * from Win32_NetworkAdapterConfiguration Where IPEnabled = True")[/COLOR]
[COLOR=#000000]For Each objAdapter In colAdapters[/COLOR]
[COLOR=#000000]Sheets("login").Range("AB25") = objAdapter.MACAddress[/COLOR]
[COLOR=#000000][INDENT]Next objAdapter[/INDENT]
[/COLOR]


công dụng cuối cùng của nó là gán địa chỉ MAC của máy tính cho ô AB25 để dùng những thuật toán mã hóa tạo CDkey nhưng tại sao lại tạo truy vấn và duyệt vòng lập trong đó
Nhân tiện các bạn biết kiểu biến Object có tác dụng gì không ạ, và khi nào mới sử dụng nó, cám ơn các bạn đã đọc bài viết​

1- Vòng lặp là để duyệt qua các Adapters của máy bạn ( ví dụ bạn lắp 2 card mạng, hoặc máy bạn có 1 Lan, 1 wifi )
2- Kiểu biến object , tức là biến đó là 1 đối tượng có thuộc tính , phương thức, việc khai báo biến tường minh có lẽ chương trình sẽ chạy nhanh hơn và rõ ràng hơn !
 
Upvote 0
Status
Không mở trả lời sau này.
Web KT

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

Back
Top Bottom