Đưa mỗi bức ảnh lên thì có khi cả mấy tháng chưa chắc đã được đâu bạn.đã loay hoay mấy ngày nay vẫn không được.
Bạn xem thử. . .Đây là file danh sách
Bài này là kinh điển kỹ thuật của nhà băng cuối ngày sort phát sinh, gộp, và tính tổng. Chỉ là ở đây, người ta làm ngược tổng từ dưới lên (ít có, nhưng không hẳn là không ai làm)Bạn xem thử. . .
Dùng mảng code chạy nhay hơnĐây là file danh sách và macro mình làm thử nhưng chạy không ra được đúng sum tổng ở các dòng dưới:
Sub Tinhtong()
Dim m As Long
Dim rA As Range
For Each rA In Range("C7", Range("F" & Rows.Count).End(xlUp)).SpecialCells(xlConstants, xlNumbers).Areas
rA.Cells(0).Formula = "=SUM(" & rA.Address & ")"
Next rA
End Sub
Sub ABC()
Dim sh As Worksheet, rng As Range, TT(), t(), sR&, i&, j&
Set sh = ThisWorkbook.Sheets("VP_2")
Set rng = sh.Range("A6:F" & sh.Range("A1000000").End(xlUp).Row)
sR = rng.Rows.Count
ReDim TT(1 To 1, 1 To 4)
ReDim t(1 To 1, 1 To 4)
For i = sR To 1 Step -1
If IsNumeric(rng(i, 1)) Then
For j = 3 To 6
t(1, j - 2) = t(1, j - 2) + rng(i, j)
TT(1, j - 2) = TT(1, j - 2) + rng(i, j)
Next j
Else
rng(i, 3).Resize(, 4) = t
rng(i, 3).Resize(, 4).Font.Bold = True
ReDim t(1 To 1, 1 To 4)
End If
Next i
sh.Range("C5").Resize(, 4) = TT
End Sub
Sub ABC_1()
Dim Sh As Worksheet, Rng As Range, TT(), t(), SoDg&, I&, J&, Col As Integer
Set Sh = ThisWorkbook.Sheets("VP_2")
Set Rng = Sh.Range("A6:F" & Sh.Range("A1000000").End(xlUp).Row)
SoDg = Rng.Rows.Count
ReDim TT(1 To 1, 1 To 4)
ReDim t(1 To 1, 1 To 4)
For I = SoDg To 1 Step -1
If IsNumeric(Rng(I, 1).Value) Then
For J = 3 To 6
t(1, J - 2) = t(1, J - 2) + Rng(I, J)
' TT(1, J - 2) = TT(1, J - 2) + Rng(I, J) '
Next J
Else
Rng(I, 3).Resize(, 4) = t
Rng(I, 3).Resize(, 4).Font.Bold = True
For Col = 1 To 4
TT(1, Col) = TT(1, Col) + t(1, Col)
Next Col
ReDim t(1 To 1, 1 To 4)
End If
Next I
Sh.Range("C5").Resize(, 4) = TT
End Sub
Cháu. Phiền chú giải thích giúp. Lỡ có người không biết như cháu nữa. Cám ơn chú ạBạn nào không biết thì lên tiếng tôi sẽ giải thích. Không thấy thì tôi coi như mọi người đều hiểu, chỉ có mình lo xa.
Úi bác phức tạp thật. Có lúc bác đưa cơm đến tận mồm, có lúc bác lại vứt cho cái nồi với cái chiếu nhậu. Copy vào nó cứ đỏ lòm là biết cần lửa, lửa xong thấy ... là thiếu gạo, gạo xong lại thấy ? là lại đi tìm rau, mà ở đô thị ra chợ thì lâu lắm, xung quanh không ai làm vườn, thế là nhịn. Thiệt là khó quá đi.Chú thêm cho các bạn nào mới bước vào khái niệm dùng mảng:
Các bạn có để ý code bài #6 của tôi dùng Erase để xóa mảng trong khi bài #7 và #8 dùng Redim để làm việc tương tự?
Bạn nào không biết thì lên tiếng tôi sẽ giải thích. Không thấy thì tôi coi như mọi người đều hiểu, chỉ có mình lo xa.
Xem code khai báo. Khi tôi dùng Dim a(1 To 10) thì a được xác định là mảng tĩnh. Khi hai bài kia khai Dim a() thì VBA hiểu là mảng động.Cháu. Phiền chú giải thích giúp. Lỡ có người không biết như cháu nữa. Cám ơn chú ạ
Bỏi tôi biết là từ Erase/ReDim dễ bị hiểu lầm cho nên tôi cố tình nói chgo bạn ở bài #10 hỏi.Úi bác phức tạp thật....
Về vấn đề chính: theo em thì Erase là xóa (không cần google dịch), Dim là định nghĩa biến => Redim là định nghĩa lại biến, mà định nghĩa lại thì nó phải xem cái cũ không tồn tại nghĩa là xóa.
...
Em đọc xong và rối tung, cơ bản là do không có cơ bản nên chịu. Em chỉ thấy khi code có array thì y rằng dưới sẽ có redim, và cứ nhớ vậy cho gọn.Xem code khai báo. Khi tôi dùng Dim a(1 To 10) thì a được xác định là mảng tĩnh. Khi hai bài kia khai Dim a() thì VBA hiểu là mảng động.
Mảng tĩnh luôn xác định vị trí cố định trong bộ nhớ, và được VBA tạo ngay lúc khai báo. Mảng động chỉ là giành trước tên biến, chưa xác định gì cả (ngoài việc nếu bạn có thêm As kiểu gì đó thì mảng bắt buộc phải là kiểu ấy).
Để trở về trị mặc định (điển hình 0 với kiểu số, "" với kiểu chuỗi,...), mảng động dùng Erase, mảng tĩnh dùng ReDim. Nói cách khác:
1. mảng tĩnh không thể ReDim. Đã tĩnh rồi cón ReDim sửa đổi số cột/dòng khỉ mốc gì nữa.
2. mảng động không thể Erase (không hẳn đúng 100%, xem phần cuối đoạn này sẽ rõ). Dùng lệnh này là bạn tách rời tên mảng ra khỏi bộ nhớ của nó. Tức là muốn dùng a kế tiếp thì bạn phải ReDim nó lại. Chả hiệu quả chút nào so với ReDim. Nhưng nếu code của bạn gặp vấn đề với lượng bộ nhớ thì Erase là cách hữu hiệu nhất để bảo đảm mảng nhả bộ nhớ ra.
Ghi chú thêm về bộ nhớ: nếu bạn gặp vấn đè với lượng bộ nhớ thì không nên dùng mảng tĩnh. Bởi vì Erase nó chả giúp cho bạn thấu về bộ nhớ. Tuy nhiên nếu vấn đề không đễn nỗi nặng và lý do chính nằm ở mảng chuỗi thì cái nào cũng được. Trong mảng chuỗi, các vị trí phần tử chỉ chứa con trỏ đến chuỗi giá trị.
Bỏi tôi biết là từ Erase/ReDim dễ bị hiểu lầm cho nên tôi cố tình nói chgo bạn ở bài #10 hỏi.
Ở đây tôi biết chỉ có mình bạn ấy và 1 bạn nữa là có thì giờ nghe chuyện "lý thuyết" của tôi. Những người khác xem trọng "thực hành" hơn.
Và thục hành ra sao tôi không biết chứ về lý thuyết thì hiểu đơn giản như vậy là SAI!
Điển hình nhất: bạn bảo ReDim là định nghĩa lại biến là sai. Chịu khó đọc câu thứ hai của phần trên. Nếu nói đúng thì phải là "lập mảng mới với kích thước mới". Lập mảng khác với định nghĩa mảng.
Khai báo (Dim) là lệnh dẫn trình dịch, xảy ra trước khi code chạy. Sửa mảng (ReDim) là lệnh bình thường, xảy ra khi code chạy.
Hồi nào tôi cứ ngỡ việc phân biệt lệnh dẫn và lệnh chạy là chuyện thực tế. Té ra bà con coi đấy là lý thuyết?
Xin lỗi tôi viết nhầm. Đúng thì phải là:...
Trên bác bôi đậm không biết là có ý đồ chiến thuật gì vậy ạ?![]()
![]()
![]()
Có vẻ không hợp lý lắm.cơ bản là do không có cơ bản
Vẫn đang suy ngẫm, chưa kịp hỏi thì anh đã điều chỉnh lại rồi.Mảng động dùng ReDim, mảng tĩnh dùng Erase (có muốn ReDim VBA cũng không cho phép).
Em thì lý thuyết không nhớ được nên phải tóm nó gọn lại.Xin lỗi tôi viết nhầm. Đúng thì phải là:
Mảng động dùng ReDim, mảng tĩnh dùng Erase (có muốn ReDim VBA cũng không cho phép).
há há há. Văn 5, 6 nên nó lại rất hợp lý.Có vẻ không hợp lý lắm.
Vẫn đang suy ngẫm, chưa kịp hỏi thì anh đã điều chỉnh lại rồi.
Đỏ: tôi có bài viết về lệnh for/next. Nó không hẳn đơn giản như bạn nghĩ....VD: array kèm redim. for cần false updating... Nói chung là làm cho dễ nhớ, quan điểm "sai thì sửa, chửa thì đẻ".![]()
![]()
![]()
Tình huống vui vẻ thôi bác.Đỏ: tôi có bài viết về lệnh for/next. Nó không hẳn đơn giản như bạn nghĩ.
Xanh: nếu bạn có con gái thì bạn có còn quan niệm ấy không? Có những việc đợi đến mới sửa sai, có những việc đaoịh đến sửa sai thì đã bút sa gà chết.
Chú: tôi hiểu chỗ dỏ, nó liên quan đến chỗ xanh. Từ next là tôi nói trại từ need (không ai Tây bồi êm bằng tôi đâu).
Tôi có nói chuyện phá hay để đâu - đó là chính kiến về xã hội. Mà nói chính kiến thì cả đời còn chưa hết....
Nhưng mà có chứ bác, nếu may mắn mà có con gái, rồi nếu đen đen mà nó rơi vào xanh xanh thì vẫn phải cho xanh chứ không cho phá được.
...
Sau khi đọc đoạn này, Chợt nhận ra bản thân cháu cũng đang mập mờ chỗ này.2. mảng động không thể Erase (không hẳn đúng 100%, xem phần cuối đoạn này sẽ rõ). Dùng lệnh này là bạn tách rời tên mảng ra khỏi bộ nhớ của nó. Tức là muốn dùng a kế tiếp thì bạn phải ReDim nó lại. Chả hiệu quả chút nào so với ReDim. Nhưng nếu code của bạn gặp vấn đề với lượng bộ nhớ thì Erase là cách hữu hiệu nhất để bảo đảm mảng nhả bộ nhớ ra.
Theo tôi thì chú thích (comment) sai.Sau khi đọc đoạn này, Chợt nhận ra bản thân cháu cũng đang mập mờ chỗ này.
...
Rõ ràng cũng dùng kiểu này mà lơ ngơ lẫn cả 2 cái luôn.
Ban đầu cháu không có cái dòng Earse và Redim đâu ạ. Thấy nó ra kết quả sai.Bởi thấy nó vẫn lưu kết quả trước đó. Rồi cho thêm 2 dòng đó vào. Trước khi đọc cái bài trên của chú. Mới phát hiện ra mình cũng đang bị vấn đề mà như chú nói ở trên ấy ạTheo tôi thì chú thích (comment) sai.
Chỗ đó đáng lẽ phải là Reset số dòng. Hiển nhiên biến K là biến đếm số dòng kết quả. Lệnh ReDim tạo mảng với cỡ max có thể xảy ra (tức là cứ mỗi dòng đàu vào sẽ tọa ra mọt dòng đầu ra.
Em đọc hết rồi nhưng chưa đủ khả năng để hiểu.Lý thuyết:
VBA không phải là ngôn ngữ dịch ra exe rồi chạy. Code VBA phải chạy trên nền tảng VBA.
Chạy trên nền tảng đặc thù thì chậm hơn code exe trên nền tảng chủ của máy (Windows, MacOS, Linux,...) nhiều. Đó là lý do chính tại sao C++ chạy nhanh hơn Java rất nhiều lần, và C nếu viết giỏi sẽ chạy nhanh gần bằng code ASM (code máy).
Một trong những cái lợi của nền tảng đặc thù là bọn này có cỗ máy dọn rác cho nên tránh được lỗi rò bộ nhớ. Nếu bạn nào đã từng viết C/C++ rồi sẽ thấy đó là cái bug đáng gờm nhất của hai ngôn ngữ này. Đổi lại, như tôi nói trên chúng có tốc độ khong thể chối cãi. Nếu bạn đọc bài của tôi nhiều sẽ thấy tôi có từng nói Pyhton dựa vào các thư viện viết bằng C cho neentoocs độ đáng nẻ, chứ chính nó chạy trên nền tảng đặc thù.
Cỗ máy dọn rác (garbage collector) là gì?
Là một phần mềm có nhiệm vụ đi gồm thâu lại những mảnh trong bộ nhớ không dùng tới nữa. Chỗ gồm thâu này sẽ lại trở thành free, các lệnh cần bộ nhớ như lệnh tạo chuỗi, lệnh tạo đối tượng (object) sẽ có nhiều chỗ trống hơn để làm việc.
Khi nào thì cỗ máy biết đấy là rác để gom về dùng lại?
Khi vùng nhớ ấy không còn cái gì trỏ vào.
Đối với chuỗi, nếu bạn gán chuỗi với trị khác thì vùng nhớ chứa trị cũ sẽ được giải nhiệm. Cỗ dọn rác chiếu vào đấy để đưa vùng nhớ này vào vùng free agents. Vì vậy, gặp chương trình dùng chuỗi quá dài thì người ta tiết kiệm biooj nhớ bằng cách dùng xong ròi thì gán "" cho nó.
Đối với mảng động thì khi bạn dùng lệnh Erase. VBA sẽ tách tên mảng ra khỏi cái vùng nhớ trên. Vùng nhớ trước đó là mảng, bây giờ là con vô thừa nhận. Và cỗ máy sẽ nhận ra chúng.
Đối với đối tượng thì khi bạn dùng lệnh Set a = đối tượng nào đó thì VBA sẽ trỏ biến a vào đối tượng ấy, cũng như ký hợp đồng mướn người. Sau đó bạn Set a= Nothing thì lệnh này tách tên biến khỏi đối tượng. Khi đôi tượng không còn biến nào trỏ vào nữa thì nó không còn ràng buộc hợp đồng nào và trở thành thất nghiệp. Và cỗ dọn rác sẽ đưa vùng nhớ của nó vào chỗ "thằng này heets xài rồi, cứ việc xiết nhà đát của nó cho thằng khác đi. Vì vậy nếu bạn đọc các code viết cẩn thận sẽ thấy người ta Set Nothing sau khi không cần dùng biến ấy nữa.
Chú thích: khi Sub/Function chạy đến lệnh Exit/End thì VBA sẽ hủy các biến khai báo nội (ngầm hay rõ gì cũng vây) trong Sub/Function. Còng việc hủy này tự động tách rời chúng ra khỏi các vùng nhớ, - trừ oại biến không bị hủy là biến Static. Việc thâu hồi vùng nhớ sau đấy vẫn theo luật tôi nêu trên.
Chú thích 2: về việc nhiều biến trỏ vào 1 đối tượng (quan hệ N-1). Đối tượng trong trường hợp này chỉ có 1. Nếu mọt trong những cong việc gây tai nạn cho nó thì các chủ hợp đòng khác sẽ thấy nó đang bị thương. Nếu nó có cái xe tải mùa bóng đá vừa rôi cầm cố mất thì tất cả chủ hợp đồng sẽ thấy nó chả tải hàng cho ai cả. Việc nó có hy vọng tiếp tục hay không tùy vào chỗ có ngân hàng nào ký với nó một cái hợp đồng cho vay tiền chuộc xe. Việc nó không khả năng tiếp tục hợp đồng cũng chả lien quan đến nó thất nghiệp hay không. Các chủ phải tự biết mà chờ nó chuộc xe hay giúp nó chuộc xe hay hủy hợp đ\ồng. Khi mọi chủ đều tuyên bố hoàn tất hoặc hủy hợp đồng thì nó mới chính thức thất nghiệp.
Nếu bạn không cần biết lý thuyết, hoặc tự cho rằng mình không đủ trình độ để hiểu thì cứ để dó. Lý thuyết này chỉ quan trọng đối với dân chuyên lập trình.Em đọc hết rồi nhưng chưa đủ khả năng để hiểu.
Em cảm ơn anh ạ.Nếu bạn không cần biết lý thuyết, hoặc tự cho rằng mình không đủ trình độ để hiểu thì cứ để dó. Lý thuyết này chỉ quan trọng đối với dân chuyên lập trình.
Là dân viết ứng dụng VBA (với dữ liệu khủng như ở GPE này) thì bạn chỉ cần biết các kiểu như thế nào là giải phóng bộ nhớ. Nhất là vùng nhớ của mảng.
- mảng chiếm hữu một vùng nhớ kiên tục trong bộ nhớ (đó là lý do chính tại sao nó hoạt động rất hiệu quả về tốc độ lẫn code.
- mảng được khai báo chứa kiểu căn bản (integer, long, single, double) thì các trị nằm đúng vị trí của phần tử trong mảng.
- các kiểu dữ liệu khác thì chỉ chứa con trỏ vào trị thật của chúng. Điển hình mảng chuỗi sẽ giành ra 10 bytes (hay 8bytes gì đó, hiện tại quên mất con số) cho mỗi phần tử để trỏ vào vùng nhớ chính thức (độ dài của chuỗi). Sau đó nếu bạn gán trị cho chuỗi thì số bytes chiếm ngự sẽ cộng thêm.
Khi bạn xóa mảng thì mọi chuỗi trở về "", các vùng chứa trị các chuỗi được giải phóng. Nếu bạn dùng lệnh Erase để xóa chuỗi thì ngoài việc giải phóng chuỗi, VBA sẽ cho giải phóng luôn cái vùng chứa con trỏ. Tùy theo người viết cân nhắc muốn xóa theo phương pháp nào.
- Chuỗi tĩnh (chuỗi được định cỡ lúc khai báo) cũng như mảng tĩnh không thể giải phóng vùng nhớ. Chúng được compiler giành chỗ rồi.
Và nếu biết sự hiện hữu của cỗ mày dọn rác thì cũng biết rằng lệnh giải phóng bộ nhớ không hẳn lập tức chuyển nó thành free. Vùng nhớ thải ra còn phải để cỗ máy dọn rác đi ngang mới hoàn toàn giải phóng. Có thể chậm hơn lúc code thực hiện 1 chút.