nguyenmanhnam
Thành viên tiêu biểu

- Tham gia
- 24/7/10
- Bài viết
- 434
- Được thích
- 266
Sao kg dùng ct subtotal mà phải viết code.Xin hộ em về tính tổng theo các thành phần (tính tổng cột C theo số thứ tự công việc ở cột A).
![]()
Do em chưa biết nhiều, ví dụ có vẻ hơi "Ngố", mong các thày giúp.
Sub TinhTong()
Dim endR&, i&, sotien As Double
Dim Arr()
With Sheet1
'Xac dong cell cuoi co du lieu o cot C tu dong 65000 - dau'
endR = .Cells(65000, 3).End(xlUp).Row
'Gan vao array cot can tinh'
Arr = .Range("A2:C" & endR).Value
End With
'Dung vong lap' UBound(Arr)= so dong cua arr
For i = UBound(Arr) To 1 Step -1 'duyt tu duoi len
If Len(Arr(i, 1)) > 0 Then 'ie o nay chua co gi
Arr(i, 3) = sotien 'gan vao C
sotien = 0
Else
sotien = sotien + Arr(i, 3)
End If
Next i
'gán vào
With Sheet1
.[A2].Resize(UBound(Arr), 3) = Arr
End With
Erase Arr
End Sub
Cách dễ nhất là duyệt từ dưới lên trên đồng thời cộng dồn vào 1 biến tạmXin hộ em về tính tổng theo các thành phần (tính tổng cột C theo số thứ tự công việc ở cột A).
![]()
Do em chưa biết nhiều, ví dụ có vẻ hơi "Ngố", mong các thày giúp.
Sub Test()
Dim Rng As Range, i As Long, Tmp As Double
Set Rng = Range("C2:C10")
For i = Rng.Rows.Count To 1 Step -1
Tmp = Tmp + Rng(i).Value
If Rng(i) = "" Then Rng(i) = Tmp: Tmp = 0
Next
End Sub
Cách đó em tự làm được ah, nhưng em mới học VBA nên chưa biết làm theo cách này ah.Sao kg dùng ct subtotal mà phải viết code.
Thưa thày, em đã bắt đầu hơi hiểu rồi, có phải cái bôi xanh hàm ý là đến đây thì những phần tính tạm cộng dồn được bao nhiêu vứt hết (cho trở về 0), dấu : có nghĩa là đồng thời ah?If Rng(i) = "" Then Rng(i) = Tmp: Tmp = 0
Thế là hiểu rồi đấyThưa thày, em đã bắt đầu hơi hiểu rồi, có phải cái bôi xanh hàm ý là đến đây thì những phần tính tạm cộng dồn được bao nhiêu vứt hết (cho trở về 0), dấu : có nghĩa là đồng thời ah?
If Rng(i) = "" Then
Rng(i) = Tmp
Tmp = 0
End If
Sub Test()
Dim Rng As Range, i As Long, Tmp As Double
Set Rng = Range("C2:C10")
For i = Rng.Rows.Count To 1 Step -1
If Rng(i) = "" Then Rng(i) = Tmp
Tmp = Tmp + Rng(i).Value
Next
End Sub
Không phải là lập vô hạn. Code vẫn chạy nhưng.. SAI. Vì khi bạn cho rác vào thùng, lý ra bạn đã hết rác (Tmp =0), bạn lại moi rác lên đi gom tiếp. Cuối cùng chỉ có cell rổng dưới cùng là đúng, còn bao nhiêu sai hếtHình như nếu em đảo thứ tự như thế này, thì có phải là một vòng tròn tính vô định không (lặp vô số lần)? Em đang tư duy hình dung, hình như là thế. Rất mong thày giúp cho.
PHP:Sub Test() Dim Rng As Range, i As Long, Tmp As Double Set Rng = Range("C2:C10") For i = Rng.Rows.Count To 1 Step -1 If Rng(i) = "" Then Rng(i) = Tmp Tmp = Tmp + Rng(i).Value Next End Sub
Thày ví dễ hiểu quá, em đã hiểu ra được bản chất vấn đề rồi. Em cảm ơn thàyKhông phải là lập vô hạn. Code vẫn chạy nhưng.. SAI. Vì khi bạn cho rác vào thùng, lý ra bạn đã hết rác (Tmp =0), bạn lại moi rác lên đi gom tiếp. Cuối cùng chỉ có cell rổng dưới cùng là đúng, còn bao nhiêu sai hết
Này nhé
If Rng(i) = "" Then Rng(i) = Tmp ===> Nếu gặp thùng rác thì cho rác đã gom vào thùng
Tmp = Tmp + Rng(i).Value ===> Đi gom tiếp, bao gồm cả việc moi luôn rác mà ta vừa bỏ vào thùng
Lý ra phải gom rác trước:
Tmp = Tmp + Rng(i).Value
rồi mới bỏ rác vào thùng (nếu gặp cái thùng):
If Rng(i) = "" Then Rng(i) = Tmp: Tmp = 0
Đằng này bạn lại làm ngược lại... Ẹc... Ẹc...
Sub Test()
Dim Rng As Range, i As Long, Tmp As Double
Set Rng = Range("C2:C10")
For i = Rng.Rows.Count To 1 Step -1
If Rng(i) = "" Then Rng(i) = Tmp: Tmp = 0 'em tưởng đến đây là cắt đuôi rồi (Tmp = 0) rồi?
Tmp = Tmp + Rng(i).Value
Next
End Sub
Thì như đã nói lần trướcEm nhìn lại vẫn thấy hơi thắc mắc 1 tí đó là nếu em đảo đi (nhưng vẫn có Tmp=0 thì tức nó vứt rác đi rồi, sao ô C2 của em lại là 108.000, trong khi đáp số đúng ra nó là 80.000 cơ mà?
PHP:Sub Test() Dim Rng As Range, i As Long, Tmp As Double Set Rng = Range("C2:C10") For i = Rng.Rows.Count To 1 Step -1 If Rng(i) = "" Then Rng(i) = Tmp: Tmp = 0 'em tưởng đến đây là cắt đuôi rồi (Tmp = 0) rồi? Tmp = Tmp + Rng(i).Value Next End Sub
Nó làm thằng này trước:Em nhìn lại vẫn thấy hơi thắc mắc 1 tí đó là nếu em đảo đi (nhưng vẫn có Tmp=0 thì tức nó vứt rác đi rồi, sao ô C2 của em lại là 108.000, trong khi đáp số đúng ra nó là 80.000 cơ mà?
PHP:Sub Test() Dim Rng As Range, i As Long, Tmp As Double Set Rng = Range("C2:C10") For i = Rng.Rows.Count To 1 Step -1 If Rng(i) = "" Then Rng(i) = Tmp: Tmp = 0 'em tưởng đến đây là cắt đuôi rồi (Tmp = 0) rồi? Tmp = Tmp + Rng(i).Value Next End Sub
If Rng(i) = "" Then Rng(i) = Tmp: Tmp = 0
Tmp = Tmp + Rng(i).Value
Sub Test()
Dim Rng As Range, i As Long, Tmp As Double
Set Rng = Range("C2:C10")
For i = Rng.Rows.Count To 1 Step -1
If Rng(i) = "" Then
Rng(i) = Tmp: Tmp = 0
Else
Tmp = Tmp + Rng(i).Value
End If
Next
End Sub
Nhưng sao lại dò như thế? duyệt từ dưới lên ở cột C, nếu ngang hàng ở cột A ="" thì Tmp=Tmp + Rng(i) ngược lại thì gán Tmp
Híc
Sub Test()
Dim Rng As Range, i As Long, Tmp As Double
Set Rng = Range("C2:C10")
For i = Rng.Rows.Count To 1 Step -1
Tmp = Tmp + Rng(i).Value
If Rng(i) = "" Then Rng(i) = Tmp: Tmp = 0
Next
End Sub
Nhân tiện bạn nguyenmanhnam đang tìm hiểu về vòng lập, tôi đố bạn 1 vấn đề
Cũng file của bạn, nhưng tôi đã gài 1 cái "bẫy". Bạn hay mở file đính kèm này và chạy code, bạn sẽ thấy code báo lỗi
Dữ liệu vẫn là thế này:
View attachment 67463
Và code vẫn thế này:
Thế mà chạy code lại báo lỗiPHP:Sub Test() Dim Rng As Range, i As Long, Tmp As Double Set Rng = Range("C2:C10") For i = Rng.Rows.Count To 1 Step -1 Tmp = Tmp + Rng(i).Value If Rng(i) = "" Then Rng(i) = Tmp: Tmp = 0 Next End Sub
Đố bạn tìm ra được nguyên nhân
Sub Test()
Dim Rng As Range, i As Long, Tmp As Double
Set Rng = Range("C2:C10")
For i = Rng.Rows.Count To 1 Step -1
If Rng(i) <> "" Then
Tmp = Tmp + Rng(i).Value
Else: Rng(i) = Tmp: Tmp = 0
End If
Next
End Sub
Em đã tìm ra nguyên nhân tại sao nó lỗi rồi, nếu ô C2 và C6 của thày em xóa (delete) đi thì lại chạy ngon. Em chưa hiểu sâu về vụ này nhưng chắc có liên quan đến vấn đề rỗng thật và giả chăng?Nhân tiện bạn nguyenmanhnam đang tìm hiểu về vòng lập, tôi đố bạn 1 vấn đề
Cũng file của bạn, nhưng tôi đã gài 1 cái "bẫy". Bạn hay mở file đính kèm này và chạy code, bạn sẽ thấy code báo lỗi
Dữ liệu vẫn là thế này:
View attachment 67463
Và code vẫn thế này:
Thế mà chạy code lại báo lỗiPHP:Sub Test() Dim Rng As Range, i As Long, Tmp As Double Set Rng = Range("C2:C10") For i = Rng.Rows.Count To 1 Step -1 Tmp = Tmp + Rng(i).Value If Rng(i) = "" Then Rng(i) = Tmp: Tmp = 0 Next End Sub
Đố bạn tìm ra được nguyên nhân
Khi Rng(i)="", tmp = tmp+ "" --> lỗi do tmp khai báo là double.
Nếu là vầy thì hết lỗi:
Hy vọng là tại nó!PHP:Sub Test() Dim Rng As Range, i As Long, Tmp As Double Set Rng = Range("C2:C10") For i = Rng.Rows.Count To 1 Step -1 If Rng(i) <> "" Then Tmp = Tmp + Rng(i).Value Else: Rng(i) = Tmp: Tmp = 0 End If Next End Sub
Vấn đề là tôi đã "bẫy" cái gì trong file này chứEm đã tìm ra nguyên nhân rồi tại sao lỗi rồi, nếu ô C2 và C6 của thày em xóa (delete) đi thì lại chạy ngon. Em chưa hiểu sâu về vụ này nhưng chắc có liên quan đến vấn đề rỗng thật và giả chăng?
Xin lỗi vì không nắm vững vấn đề, đúng là delete các ô trống thì code mới chạy...Vấn đề là tôi đã "bẫy" cái gì trong file này chứ
Bạn cũng thấy file của bạn đâu bị gì, sao file của tôi cũng y chang thế lại lỗi?
Ẹc... Ẹc...
Nói chung, bạn nguyenmanhnam đã tìm ra 99% nguyên nhân rồi. Nếu bạn cũng tự tay làm được cái "bẫy" này thì bạn đã hiểu rõ nguyên nhân
------------
Ở đây tôi muốn nói đến vấn đề bẫy lỗi. Viết code đã khó, nghĩ ra được những lỗi có thể xãy ra lại càng khó hơn
(mà đã vấn thân vào bộ môn lập trình thì mấy vụ bẫy lỗi sẽ theo ta suốt đời đấy)
Người ta thường bị lỗi như thế này:Xin lỗi vì không nắm vững vấn đề, đúng là delete các ô trống thì code mới chạy...
Chưa nghĩ ra cái bẫy ở đâu!
Sub Test()
Dim Rng As Range, i As Long, Tmp As Double
Set Rng = Range("C2:C10")
For i = Rng.Rows.Count To 1 Step -1
If Rng(i).Value <> "" Then
Tmp = Tmp + Rng(i).Value
Else
Rng(i) = Tmp: Tmp = 0
End If
Next
End Sub
Xin mọi người giúp em hiểu là tại sao khi ấn câu này ở đầu thì nó lại tính ah?- Dùng On Error Resume Next ở đầu code
Ạh... nó chẳng tính gì đâu, chẳng qua để câu đó, nếu gặp lỗi nó đi luôn thôiXin mọi người giúp em hiểu là tại sao khi ấn câu này ở đầu thì nó lại tính ah?
Em chưa hiểu lắm về tại sao lại phải thực hiện gán (các dòng bôi xanh), em cứ tưởng công thức tại dòng (bôi đỏ) chính là gán rồi. Phải chăng nó chỉ có tác dụng nhằm loại bỏ dòng 1 (là dòng tiêu đề chữ sẽ không tính toán được)?. Nhưng hình như cũng không phải vì em xóa đoạn bôi xanh đi, xóa nốt tiêu đề dòng em mà Code vẫn không chạy. Đặc biệt là dòng Erase Arr không biết có tác dụng gì ah?. Xin được kính nhờ các thày giải thích hộ em.Sao kg dùng ct subtotal mà phải viết code.
Bạn xem coe nhé, xét theo cột A và tính tổng cột C.
Sub TinhTong()
Dim endR&, i&, sotien As Double
Dim Arr()
With Sheet1
'Xac dong cell cuoi co du lieu o cot C tu dong 65000 - dau'
endR = .Cells(65000, 3).End(xlUp).Row
'Gan vao array cot can tinh'
Arr = .Range("A2:C" & endR).Value
End With
'Dung vong lap' UBound(Arr)= so dong cua arr
For i = UBound(Arr) To 1 Step -1 'duyt tu duoi len
If Len(Arr(i, 1)) > 0 Then 'ie o nay chua co gi
Arr(i, 3) = sotien 'gan vao C
sotien = 0
Else
sotien = sotien + Arr(i, 3)
End If
Next i
'gán vào
With Sheet1
.[A2].Resize(UBound(Arr), 3) = Arr
End With
Erase Arr
End Sub
Nếu file ex 2007 thì save thành xlsm
Thôi, bạn đừng tìm hiểu chi cho mất công! Cái đó người ta dùng phương pháp xử lý mảng. Tuy rằng tốc độ làm việc của code là vô địch nhưng rất khó hiểuEm chưa hiểu lắm về tại sao lại phải thực hiện gán (các dòng bôi xanh), em cứ tưởng công thức tại dòng (bôi đỏ) chính là gán rồi. Phải chăng nó chỉ có tác dụng nhằm loại bỏ dòng 1 (là dòng tiêu đề chữ sẽ không tính toán được)?. Nhưng hình như cũng không phải vì em xóa đoạn bôi xanh đi, xóa nốt tiêu đề dòng em mà Code vẫn không chạy. Đặc biệt là dòng Erase Arr không biết có tác dụng gì ah?. Xin được kính nhờ các thày giải thích hộ em.
With Sheet1
.[A2].Resize(UBound(Arr), 3) = Arr
End With
Nếu là công thức mảng bình thường trong Excel thì em cũng có thể hiểu được.Thôi, bạn đừng tìm hiểu chi cho mất công! Cái đó người ta dùng phương pháp xử lý mảng. Tuy rằng tốc độ làm việc của code là vô địch nhưng rất khó hiểu
Bạn cứ thông thả nghiên cứu, khi nào rành hết về vòng lập rồi hẳn nghiên cứu tiếp về mảng cũng chưa muộn
Lấy bài toán tạo STT cho bạn hình dung.Nếu là công thức mảng bình thường trong Excel thì em cũng có thể hiểu được.
Em đọc ở phần trên em cũng biết được phần nào bản chất xử lý của nó, tiện đây xin thày chỉ giúp hộ em với ah.
Sub STT1()
Dim i As Long
For i = 1 To 50000
Cells(i, 1) = i
Next
End Sub
Sub STT2()
Dim i As Long, Arr()
ReDim Arr(1 To 50000, 1 To 1)
For i = 1 To 50000
Arr(i, 1) = i
Next
Range("A1:A50000").Value = Arr
''Hoac Range("A1").Resize(UBound(Arr)).Value = Arr
End Sub
Vâng, hình như em không tỉnh táo nên nhầm lẫn 2 đối tượng Arr(i,1) nó khác hẳn với Rng(i)trong bài của thày. Em sẽ xem lại ngayLấy bài toán tạo STT cho bạn hình dung.
Sub STT2()
Dim i As Long, Arr()
ReDim Arr(1 To 50000, 1 To 1)
For i = 1 To 50000
Arr(i, 1) = i
Next
Range("A1:A50000").Value = Arr
''Hoac Range("A1").Resize(UBound(Arr)).Value = Arr
Lấy bài toán tạo STT cho bạn hình dung.
Hãy chạy 2 code và so sánh tốc độ xem cái nào nhanh hơn và thử mường tượng xem bạn hiểu được thứ gì
Hãy chạy 2 code và so sánh tốc độ xem cái nào nhanh hơn và thử mường tượng xem bạn hiểu được thứ gì
Bạn có thể hiểu đơn giản thế này:Em hiểu rồi, trong ví dụ cụ thể bài này thì bản chất khác nhau ở dòng bôi đỏ được đưa vào vị trí trước hay là sau, chính điều đó tạo sự khác biệt về tốc độ giúp công thức mảng nhanh hơn.
Đặc biệt là dòng Erase Arr không biết có tác dụng gì ah?
Xóa mảng cho đỡ tốn bộ nhớ máy, mình nghĩ bạn muốn học mảng Arr trong VBA thì qua đây nè bạn chúc bạn thành côngErase Arr không biết có tác dụng gì ah?.
Arr = .Range("A2:C" & endR).Value ---> là đưa toàn bộ giá trị trong từng cell của vùng "A2:C" & endR vào Arr và đương nhiên Arr trở thành 1 mảng 2 chiều (thế nên mới cần .Value... mà thật ra không có .Value nó vẫn hiểu)Em vẫn lơ mơ chưa phần biệt được sự khác nhau giữa Range và mảng, cụ thể trong bài giải của thày ptm0412 và thày ndu:
Arr = .Range("A2:C" & endR).Value
Set Rng = Range("C2:C10")
Tức là em thắc mắc tại sao mảng (Arr) lại có Value đi cùng trong khi đó Rng lại không, nghĩa là tại sao không là:
Set Rng = Range("C2:C10").Value?
Một số kí hiệu khi khai báo biến có nghĩa là gì (các kí hiệu mà em bôi màu đỏ):
Dim endR&, i&, sotien As Double
Dim Arr()
Vì chưa biết nhiều về VBA, xin được mọi người giúp đỡ.
Sub Test()
Dim i&
MsgBox TypeName(i)
End Sub
Cũng chẳng biết nói thế nào nữa. Tóm lại làm nhiều sẽ tự ngộ ra vấn đềXin thày hãy chỉ giúp hộ em chút nữa sự khác nhau giữa Mảng và Range, cách chuyển đổi giữa 2 cái này.</span><br />Về khai báo em thấy nó cứ gần giống nhau, chẳng lẽ nguyên nhân “do cái tên” khi khai biến cách đặt tên một cái là ….as Range và một cái là Dim…() mà về cuối Range kết quả ngay, trong khi cái kia phải gán một lần nữa mới ra ah.</span><br />
Sao kg dùng ct subtotal mà phải viết code.
Bạn xem coe nhé, xét theo cột A và tính tổng cột C.
Nếu file ex 2007 thì save thành xlsmPHP:Sub TinhTong() Dim endR&, i&, sotien As Double Dim Arr() With Sheet1 'Xac dong cell cuoi co du lieu o cot C tu dong 65000 - dau' endR = .Cells(65000, 3).End(xlUp).Row 'Gan vao array cot can tinh' Arr = .Range("A2:C" & endR).Value End With 'Dung vong lap' UBound(Arr)= so dong cua arr For i = UBound(Arr) To 1 Step -1 'duyt tu duoi len If Len(Arr(i, 1)) > 0 Then 'ie o nay chua co gi Arr(i, 3) = sotien 'gan vao C sotien = 0 Else sotien = sotien + Arr(i, 3) End If Next i 'gán vào With Sheet1 .[A2].Resize(UBound(Arr), 3) = Arr End With Erase Arr End Sub
Với điều kiện dữ liệu này bạn làm như thế này xem saoEm xin hỏi nếu làm theo công thức mảng mà bây giờ em muốn thuật toán của bài đi theo chiều từ trên xuống dưới (ngược chiều với cách trên của bác Thunghi) thì bây giời em phải làm sao ah?
Sub testtong()
Dim arr, arrkq, lRow As Long, kqrow As Long
Range("c2,c6").ClearContents
arr = Range("c2:c10").Value
For lRow = 1 To UBound(arr, 1)
If arr(lRow, 1) = "" Then
kqrow = lRow
arrkq = 0
End If
arrkq = arrkq + arr(lRow, 1)
Cells(kqrow + 1, 3).Value = arrkq
Next
End Sub
Sao kg dùng ct subtotal mà phải viết code.
Bạn xem coe nhé, xét theo cột A và tính tổng cột C.
Nếu file ex 2007 thì save thành xlsmPHP:Sub TinhTong() Dim endR&, i&, sotien As Double Dim Arr() With Sheet1 'Xac dong cell cuoi co du lieu o cot C tu dong 65000 - dau' endR = .Cells(65000, 3).End(xlUp).Row 'Gan vao array cot can tinh' Arr = .Range("A2:C" & endR).Value End With 'Dung vong lap' UBound(Arr)= so dong cua arr For i = UBound(Arr) To 1 Step -1 'duyt tu duoi len If Len(Arr(i, 1)) > 0 Then 'ie o nay chua co gi Arr(i, 3) = sotien 'gan vao C sotien = 0 Else sotien = sotien + Arr(i, 3) End If Next i 'gán vào With Sheet1 .[A2].Resize(UBound(Arr), 3) = Arr End With Erase Arr End Sub
Sub TinhTong()
Dim endR&, i&, sotien As Double
Dim Arr()
With Sheet1
'Xac dong cell cuoi co du lieu o cot C tu dong 65000 - dau'
endR = .Cells(65000, 3).End(xlUp).Row
'Gan vao array cot can tinh'
Arr = .Range("A2:C" & endR).Value
End With
'Dung vong lap' UBound(Arr)= so dong cua arr
For i = UBound(Arr) To 1 Step -1 'duyt tu duoi len
If Len(Arr(i, 1)) > 0 Then 'ie o nay chua co gi
Arr(i, 3) = sotien 'gan vao C
sotien = 0
Else
sotien = sotien + Arr(i, 3)
End If
Next i
End Sub
Không có đoạn này thì bạn không thấy kết quả trên sheet đâu bạn đoạn này rất rất quan trọng, dữ liệu sao khi tính toán được gán vào trong mảng thì phải xuất ra chứ không lẽ để trong mảng nói chung bạn dùng mảng để tính toán tạm rồi lấy cái tạm đó raEm suy nghĩ mãi mà chưa ra đươc sự cần thiết của đoạn:
With Sheet1
.[A2].Resize(UBound(Arr), 3) = Arr
End With
Erase Arr
để làm gì?
Với điều kiện dữ liệu này bạn làm như thế này xem sao
PHP:Sub testtong() Dim arr, arrkq, lRow As Long, kqrow As Long Range("c2,c6").ClearContents arr = Range("c2:c10").Value For lRow = 1 To UBound(arr, 1) If arr(lRow, 1) = "" Then kqrow = lRow arrkq = 0 End If arrkq = arrkq + arr(lRow, 1) Cells(kqrow + 1, 3).Value = arrkq Next End Sub
Em cũng đang vướng vấn đề này, mọi người chỉ giúp em cách với ạ. Em cảm ơn!Xin hộ em về tính tổng theo các thành phần (tính tổng cột C theo số thứ tự công việc ở cột A).
![]()
Do em chưa biết nhiều, ví dụ có vẻ hơi "Ngố", mong các thày giúp.
Có công đào mộ rồi, mà không chịu mở nắp ra nữa...Em cũng đang vướng vấn đề này, mọi người chỉ giúp em cách với ạ. Em cảm ơn!