Nhờ tính tổng theo các thành phần bằng VBA (1 người xem)

Liên hệ QC

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

nguyenmanhnam

Thành viên tiêu biểu
Tham gia
24/7/10
Bài viết
434
Được thích
266
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).
TongTPbangVBA.jpg


Do em chưa biết nhiều, ví dụ có vẻ hơi "Ngố", mong các thày giúp.
 

File đính kèm

Lần chỉnh sửa cuối:
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).
TongTPbangVBA.jpg


Do em chưa biết nhiều, ví dụ có vẻ hơi "Ngố", mong các thày giúp.
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.
PHP:
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
 
Upvote 0
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).
TongTPbangVBA.jpg


Do em chưa biết nhiều, ví dụ có vẻ hơi "Ngố", mong các thày giúp.
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ạm
Khi gặp cell rổng, gán giá trị biến tạm vào cell rổng ấy đồng thời cho biến tạm = 0
Ví dụ thế này:
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
   Tmp = Tmp + Rng(i).Value
   If Rng(i) = "" Then Rng(i) = Tmp: Tmp = 0
  Next
End Sub
ThuNghi chơi mảng người ta không tiêu hóa nỗi đâu (người ta mới học mà)
 
Upvote 0
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?
Thế là hiểu rồi đấy
Dấu hai chấm là để viết cho gọn thôi. Nếu viết đầy đủ thì sẽ thế này:
PHP:
If Rng(i) = "" Then
  Rng(i) = Tmp
  Tmp = 0
End If
Hai chấm để khỏi xuống dòng ấy mà
------
Nói thêm: Thuật toán này giống như việc người ta đi gom rác. Bắt đầu gom, đến khi gặp cái thùng thì cho hết rác đã gom vào (hết rác), lại đi gom tiếp
Vậy phải bắt đầu đi từ phía có rác trước chứ không thể bắt đầu đi từ phía có thùng rác, đúng không?
Từ suy luận này, nếu sửa bài toán lại, cho cell rổng nằm ở dưới thì ta phải For... Next từ trên xuống! Thế thôi
 
Lần chỉnh sửa cuối:
Upvote 0
Hì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ế. Hay là nó chỉ bị tính trùng 1 lần, tức là sau khi qua ô C6 thì Tmp = 28 (do tích lũy ở dưới lên) + 28 (do Rng tại ô C6) = 56? 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
 
Lần chỉnh sửa cuối:
Upvote 0
Hì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
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ế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...
 
Lần chỉnh sửa cuối:
Upvote 0
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ế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...
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ày
 
Upvote 0
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
 
Lần chỉnh sửa cuối:
Upvote 0
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
Thì như đã nói lần trước
Tmp = Tmp + Rng(i).Value là lấy giá trị tạm cộng thêm giá trị tại cell vừa duyệt đến. Ở tại vị trí cell rổng, cho Tmp vào và cho dù đã đặt Tmp = 0 thì khi Tmp = Tmp + Rng(i).Value có phải nó đã lấy tiếp giá trị vừa cho vào không (vì khi ấy Rng(i).Value có giá trị = Tmp ta vừa cho vào)
Còn như ta làm theo thứ tự
Tmp = Tmp + Rng(i).Value
If Rng(i) = "" Then Rng(i) = Tmp: Tmp = 0

thì lại khác. Tại vị trí cell rổng Tmp = Tmp + Rng(i).Value chẳng ảnh hưởng gì vì Rng(i) khi ấy đang = 0
Tiếp theo ta mới xét xem Rng(i) có rổng hay không để cho cho Tmp vào và đặt Tmp = 0
Bạn thấy đấy: Làm cái gì trước, cái gì sau phải tính cho kỹ, nếu không là sai tất
----------------
Tôi sẽ mô tả 2 cách làm
1> Cách của tôi:
- Gom rác
- Gặp thùng rác cũng gom luôn (thùng chưa có gì nên dù có gom cũng chẳng ảnh hưởng đến lượng rác)
- Tiếp theo, vì đã gặp cái thùng nên cho rác vào thùng (Rng(i).Value = Tmp) và ta xác nhận ta hết rác (Tmp = 0)
- Đi tiếp
2> Cách của bạn

- Đi gom rác nhưng bạn có ý tìm cái thùng trước thay vì tìm rác trước.
- Cứ gặp thùng rác thì cho rác vào
- Gom rác tiếp, bao gồm cả rác vừa bỏ vào thùng
--------------
2 cách làm hoàn toàn khác nhau mà bạn. Tôi gôm rác trước mới cho vào thùng, còn bạn thì cho vào thùng trước mới gom rác. Vì thế bạn đã gom.. nhầm
Ẹc... ẹc...
 
Lần chỉnh sửa cuối:
Upvote 0
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
Nó làm thằng này trước:
Mã:
If Rng(i) = "" Then Rng(i) = Tmp: Tmp = 0
Lúc này code gán vào cell Rng(i)=28000: tpm=0
Bi giờ code làm tới em này:
Mã:
Tmp = Tmp + Rng(i).Value
thì Tmp=28000 là đúng zồi chứ sao. Híc
Muốn làm kiểu đó code như thế này:
Mã:
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
 
Upvote 0
Hihi, bây giờ em đã hiểu được 100% vấn đề rồi, đa tạ các thày rất nhiều. Em sẽ cố gắng làm sao một thời gian ngắn bản thân em có thể giải quyết được những bài đơn giản.
 
Upvote 0
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:

untitled.JPG

Và code vẫn thế này:
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
   Tmp = Tmp + Rng(i).Value
   If Rng(i) = "" Then Rng(i) = Tmp: Tmp = 0
  Next
End Sub
Thế mà chạy code lại báo lỗi
Đố bạn tìm ra được nguyên nhân
 

File đính kèm

Upvote 0
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:
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
   Tmp = Tmp + Rng(i).Value
   If Rng(i) = "" Then Rng(i) = Tmp: Tmp = 0
  Next
End Sub
Thế mà chạy code lại báo lỗi
Đố 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:
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
Hy vọng là tại nó!
 
Upvote 0
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:
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
   Tmp = Tmp + Rng(i).Value
   If Rng(i) = "" Then Rng(i) = Tmp: Tmp = 0
  Next
End Sub
Thế mà chạy code lại báo lỗi
Đố bạn tìm ra được nguyên nhân
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?
 
Lần chỉnh sửa cuối:
Upvote 0
Khi Rng(i)="", tmp = tmp+ "" --> lỗi do tmp khai báo là double.
Nếu là vầy thì hết lỗi:
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
Hy vọng là tại nó!
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?
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)
 
Lần chỉnh sửa cuối:
Upvote 0
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)
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!
 
Lần chỉnh sửa cuối:
Upvote 0
Thử làm như thế này:
Nhập công thức =IF(A2<>"";"";1) vào ô nào đó.
Copy ô này, Paste Value vào ô C2 và C6, Code bị lỗi!
Thằng code này hổng hiểu cái vụ "" khi paste value trở thành cái gì?
 
Lần chỉnh sửa cuối:
Upvote 0
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!
Người ta thường bị lỗi như thế này:
- Giả sự tại sheet1, cột C có công thức dạng:
=IF(A1 = "","", VLOOKUP(....))
- Trong cột C này có những cell chứa giá trị rổng do công thức trả về
- Bây giờ mình copy dữ liệu sheet1, paste sang sheet2 nhưng Paste Value
- Ở sheet2, bây giờ những cell mà ta nhìn thấy là rổng thực chất nó không rổng, đó gọi là cell chứa CHUỔI RỔNG (không phải Empty Cell)
- Với những cell dạng này ta không thể cộng trừ nhân chia được
- Thí nghiệm bằng cách bấm Ctrl + G\Special\Blanks sẽ thấy mấy cell này không được chọn
----------------------------------
Trở lại file của tôi. Tôi chỉ cần gõ vào 1 cell nào đó công thức ="" xong, tôi copy cell này, paste value vào C6 hoặc C2 là code bị lỗi (tại dòng Tmp = Tmp + Rng(i).Value)
Để tránh lỗi có nhiều cách:
- Dùng On Error Resume Next ở đầu code
- Tránh lỗi trực tiếp
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).Value <> "" Then
     Tmp = Tmp + Rng(i).Value
   Else
     Rng(i) = Tmp: Tmp = 0
   End If
  Next
End Sub
vân vân... nói chung, để bẫy lỗi bắt buộc ta phải hiểu chính xác lỗi xuất hiện do nguyên nhân gì
 
Upvote 0
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?
Ạh... nó chẳng tính gì đâu, chẳng qua để câu đó, nếu gặp lỗi nó đi luôn thôi
Tức khi gặp cell rổng, giá trị Tmp + "" sẽ lỗi và nó đi luôn, Tmp vẫn giữ nguyên giá trị không tăng thêm tí nào
 
Upvote 0
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
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.
 
Lần chỉnh sửa cuối:
Upvote 0
.[A2].Resize(UBound(Arr), 3) = Arr không hiểu có tác dụng gì?

With Sheet1
.[A2].Resize(UBound(Arr), 3) = Arr
End With
Erase Arr
Xin mọi người giải thích hộ em về sự cần thiết của 3 dòng này, em nghiên cứu mãi mà chưa được.
 
Upvote 0
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.
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
----------
Tóm lại người ta đưa toàn bộ dữ liệu (từ cột A đến cột C) vào 1 mảng và tính toán trên đó. Sau khi tính xong (cũng gần giống với cách tính của chúng ta) người ta lại gán mảng đã tính vào bảng tính bằng câu lệnh:
PHP:
With Sheet1
.[A2].Resize(UBound(Arr), 3) = Arr
End With
Vậy thôi
 
Lần chỉnh sửa cuối:
Upvote 0
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
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.
 
Upvote 0
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.
Lấy bài toán tạo STT cho bạn hình dung.
1> Theo cách thông thường, để tạo số thứ tự từ 1 đến 50000 ta làm như sau:
PHP:
Sub STT1()
  Dim i As Long
  For i = 1 To 50000
    Cells(i, 1) = i
  Next
End Sub
2> Bằng phương pháp mảng thì người ta làm bài toán trên như vầy:
PHP:
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
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ì
 
Upvote 0
Lấ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
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 ngay
 
Lần chỉnh sửa cuối:
Upvote 0
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ì

Cách 2 chạy nhanh hơn, em hiểu thế này có đúng không hả thày, nếu có gì sai mong thày chỉ bảo:
Cách 1 lâu hơn là bởi tính toán xong nó hiện ra màn hình xong tức ra sản phẩm cuối cùng (làm hết quy trình xong mới đi tiếp).
Cách 2 nó chỉ tính toán sơ bộ nhớ vào biến tạm Arr(i,1) tạm trong máy tính (chưa hiện ra màn hình vội) kiểu tựa như tắt tạm chức năng hiện ra trước đi tiếp cho nhanh, sau khi tính toán sơ bộ cho cả mảng thì đổ bộ 1 lúc ra toàn bộ kết quả ra. Bởi vậy nhanh hơn?.

Giải thích nôm na theo kiểu dân gian:
Cách 1: Nhặt được 1 quả bóng chạy vào vị trí cần để sau đó mới chạy ra nhặt quả thứ 2...đến quả 5.000 (tốn thời gian chạy trên đường vào chỗ cần để).

Cách 2: Lấy tạm cái rổ nào đó, vừa cầm vừa cho vào rổ, khi nhặt được hết rồi thì mới đổ toàn bộ vào vị trí của nó.
em hiểu như vậy không biết có gì sai không ah?

Tức là 1 thằng tính tạm xong mới gán thể hiện ở dòng Range("A1:A50000").Value = Arr đặt ở cuối, còn cái kia thì gán ngay ban đầu.
 
Lần chỉnh sửa cuối:
Upvote 0
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ì

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ách 1 (tốc độ nhanh hơn):
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 2 (tốc độ chậm hơn 1 chút):
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
 
Upvote 0
Theo mình hiểu như thế này:
VD: Dữ liệu của Bạn từ A1:A10. Bây giờ yêu cầu xử lý dữ liệu bên mảng A1:A10 vào cho kết quả bên B1:B10
C1: Bạn xử lý A1 -> Sau đó copy dán ngày vào B1. Tiếp theo A2 -> B2.....
C2: Xử lý 1 lần số liệu bên A1, A2...A10 sau đó copy từ A1:A10 và dán vào B1:B10 là xong
=> cách 2 giảm được 9 lần copy.
 
Upvote 0
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.
Bạn có thể hiểu đơn giản thế này:
- Bất cứ thủ tục nào thực hiện TÍNH TOÁN TRỰC TIẾP TRÊN CELL đều cho tốc độ chậm
- Nếu người ta cho mọi thứ vào mảng và tính toán trên đó, xong việc lại gán kết quả vào bảng tính thì tốc độ sẽ nhanh hơn
--------------
Có thể mường tượng như thế này:
- Bạn vừa được phân công quản lý 1 phân xưởng có 100 công nhân
- Bạn dự tính sẽ phân bố lại vị trí làm việc cho từng công nhân và bạn đã làm như sau:
1> Cách 1: Đích thân dẫn từng công nhân đến từng vị trí làm việc (làm xong cũng vã mồ hôi)
2> Cách 2: Về văn phòng, soạn 1 bảng phân công trên giấy rồi đưa cho người ta xem để người ta tự mình đến vị trí làm việc như đã ghi trên giấy (khỏe re)
- Xem qua cũng biết cách nào tối ưu hơn rồi
 
Upvote 0
Giúp em hiểu một số đối tượng trong VBA

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 đỡ.
 
Upvote 0
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 đỡ.
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)
Set Rng = Range("C2:C10") ---> bất cứ biến nào thuộc dạng biến đối tượng đều phải có động tác Set (chẳng hạn là Range, Workbook, Worksheet, Object... vân vân...). Khi ta thực hiện lệnh Set Rng = Range("C2:C10") thì mục đích của ta là muốn nói mọi thứ thuộc về vùng Range("C2:C10"), chứ không riêng gì Value (như giá trị, công thức, màu sắc, font chữ....)
--------------------------
Dim Arr() ---> Cái này xác định chính xác Arr chính là 1 mảng. Xin lưu ý thêm rằng nếu ta thấy lệnh như vầy Dim Arr() as Long thì không có nghĩa Arr là biến Long mà phải hiểu rằng Arr là 1 mảng chứa những giá trị thuộc biến Long
Dim endR&, i& ---> Cái này tôi không chắc lắm nhưng nếu tôi đoán không lầm thì nó tương đương với Dim endR as Long, i as Long
Có thể thí nghiệm để kiểm chứng
PHP:
Sub Test()
  Dim i&
  MsgBox TypeName(i)
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Xin chỉ rõ hơn hộ em về sự khác nhau giữa mảng và Range

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 />
 
Upvote 0
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 />
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 đề
Có thể mường tượng thế này: Range là THỰC còn mảng là ẢO
- 1 cánh đồng đã được chia thành nhiều thửa ruộng, đó là THỰC (Range)
- 1 bản vẽ cánh đồng trên giấy, đó là ẢO (Array)
---------------
- Range bao gồm nhiều thành phần trong đó như Value, Color, Font... vân vân (như đã nói ở trên)
- Array chỉ là những giá trị (Value)... ----> Cái này có thể chưa đúng nhưng tạm hiểu vậy đi
Thật ra Range và Array chẳng liên quan gì nhau cả, chẳng qua khi cần thiết người ta mới dùng 1 phương pháp nào đó để chuyển đổi qua lại thôi
Khai báo đương nhiên đã xác định được biến là cái gì rồi. Ví dụ: Dim Arr as Range thì đương nhiên Arr là biến Range, còn nếu Dim Arr() thì đó là Array
Để chuyển từ Range sang Array, chỉ cần Arr = Range(...).Value
Đê chuyển từ Array sang Range, chỉ cẩn Range(...).Value = Arr
Chuyển đổi thật đơn giản
 
Lần chỉnh sửa cuối:
Upvote 0
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.
PHP:
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

Em 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?
 
Upvote 0
Em 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?
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
 
Upvote 0
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.
PHP:
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

Em 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ì?
Bởi em cứ nghĩ đoạn thế này là đủ thôi chứ:
PHP:
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

Rất mong mọi người chỉ giúp em.
 
Upvote 0
Em 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ì?

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 đó ra
 
Upvote 0
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 phân tích mãi mà chưa hiểu, mong các bác giải thích nghĩa đoạn Code hộ em.
 
Upvote 0

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

Back
Top Bottom