Các câu hỏi về mảng trong VBA (Array)

Liên hệ QC

viehoai

Thành viên gắn bó
Tham gia
22/5/09
Bài viết
2,599
Được thích
2,906
Xin các anh chị giúp đỡ Code Gán các giá trị của một Range là các phần tử của Mãng
Ví dụ: Tôi có các giá trị của Range("A1:A10"). Tôi muốn viết code để gán giá trị của các cells từ A1:A10 là các phần tử của Mãng Arr chẳn hạn.
Xin cảm ơn các anh chị
 
Theo như file thì bạn muốn tính tổng các số 1, 2, 3.. hay là I, II,.. hay cả hai?
(Mình thấy trong file 1, 2, 3,.. đã có số liệu nên bạn chỉ cần tính tổng của I, II)
Bạn nói rõ hơn rồi mình bàn tiếp
Cả 2 bác ah, ban đầu tính tổng củ 1,2,3...sau đó tính nhóm I, II...( trong file đính kèm I = 1 + 2 tức B8=B9+B14 ). Tức là tôi muốn tính tổng hợp theo 2 cấp.
 
Upvote 0
Cả 2 bác ah, ban đầu tính tổng củ 1,2,3...sau đó tính nhóm I, II...( trong file đính kèm I = 1 + 2 tức B8=B9+B14 ). Tức là tôi muốn tính tổng hợp theo 2 cấp.
Vậy mình sửa theo code của bạn thử nhé
PHP:
Sub tinhtong()
Dim DL(), i As Long, Dongcuoi, Tmp, Congviec, Tong
Dongcuoi = [B65000].End(xlUp).Row
DL = Range("A8:B" & Dongcuoi).Value
On Error Resume Next
For i = UBound(DL, 1) To 1 Step -1If DL(i, 1) = "" Then
Tmp = Tmp + DL(i, 2)
ElseIf DL(i, 1) <> "" And IsNumeric(DL(i, 1)) Then
DL(i, 2) = Tmp
'Congviec = i
Tong = Tong + DL(i, 2)Tmp = 0
Else DL(i, 2) = TongTong = 0
End If
Next i
Range("A8:B" & Dongcuoi).Value = DL
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Làm như bác trong trường hợp dữ liệu bài trên là ổn, code

PHP:
Sub tinhtong()
Dim DL(), i As Long, Dongcuoi, Tmp, Congviec, Tong
Dongcuoi = [B65000].End(xlUp).Row
DL = Range("A8:B" & Dongcuoi).Value
On Error Resume Next
For i = UBound(DL, 1) To 1 Step -1
If DL(i, 1) = "" Then
Tmp = Tmp + DL(i, 2)
ElseIf DL(i, 1) <> "" And IsNumeric(DL(i, 1)) Then
DL(i, 2) = Tmp
Congviec = i
Tong = Tong + DL(i, 2)
Tmp = 0
Else: DL(i, 2) = Tong
Tong = 0
End If
Next i
Range("A8:B" & Dongcuoi).Value = DL
End Sub

Tuy nhiên, để khắc phục hiện tượng bị lỗi theo cách tôi làm (Khi i=1 thì Dl(i-1,1)=??? báo lỗi).

Bác đưa ra giải pháp là I và II nó không phải là số, nhưng nếu giả sử áp dụng vào bài toán khác nếu số thứ tự cần tính tổng ở 2 cấp độ cùng là số hoặc Text thì làm sao
(1,2 biến thành a, b thì sao).

Em ví dụ theo file đính kèm ở dưới

Không lẽ ta phải duyệt từ trên xuống dưới hả bác?
 

File đính kèm

  • Tinh tong 2.xls
    18.5 KB · Đọc: 38
Upvote 0
Tuy nhiên, để khắc phục hiện tượng bị lỗi theo cách tôi làm (Khi i=1 thì Dl(i-1,1)=??? báo lỗi).

Bác đưa ra giải pháp là I và II nó không phải là số, nhưng nếu giả sử áp dụng vào bài toán khác nếu số thứ tự cần tính tổng ở 2 cấp độ cùng là số hoặc Text thì làm sao
(1,2 biến thành a, b thì sao).

Em ví dụ theo file đính kèm ở dưới

Không lẽ ta phải duyệt từ trên xuống dưới hả bác?
Nói chung để code chạy thì bạn phải chỉ ra được sự khác nhau của 2 kiểu dữ liệu (ví dụ loại thứ nhất luôn là chữ I chẳng hạn) ---> Nếu không làm rõ được điều này và nay nhập vầy, mai lại nhập khác thì code nó biết đường đâu mà lần
 
Upvote 0
Nói chung để code chạy thì bạn phải chỉ ra được sự khác nhau của 2 kiểu dữ liệu (ví dụ loại thứ nhất luôn là chữ I chẳng hạn) ---> Nếu không làm rõ được điều này và nay nhập vầy, mai lại nhập khác thì code nó biết đường đâu mà lần

Dấu hiệu để nhận diện chỉ ra được sự khác nhau của 2 kiểu dữ liệu trong tất cả các file thực tế công việc của tôi là: Các dòng tổng lớn (ứng với I, II trong bài này) luôn nằm trên các dòng tổng nhỏ tức ô ngay dưới nó không phải ô trắng khác với các dòng tổng nhỏ ô liền dưới nó là ô trắng (rỗng).

Trong Code:
PHP:
Sub tinhtong()
Dim DL(), i As Long, Dongcuoi, Tmp, Congviec, Tong
Dongcuoi = [B65000].End(xlUp).Row
DL = Range("A8:B" & Dongcuoi).Value
For i = UBound(DL, 1) To 1 Step -1
If DL(i, 1) = "" Then
Tmp = Tmp + DL(i, 2)
ElseIf DL(i, 1) <> "" And DL(i - 1, 1) <> "" Then
DL(i, 2) = Tmp
Congviec = i
Tong = Tong + DL(Congviec, 2)
Tmp = 0
Else
DL(i, 2) = Tong
Tong = 0
End If
Next i
Range("A8:B" & Dongcuoi).Value = DL
End Sub
Nó có nhược điểm là ô trên cùng DL(i - 1, 1) = DL(0,1) nên bị lỗi, tôi chưa nghĩ ra cách nào để sửa cả.
Xin thày Ndu và mọi người gợi ý cho giải pháp để khắc phục.
 
Lần chỉnh sửa cuối:
Upvote 0
Dấu hiệu để nhận diện chỉ ra được sự khác nhau của 2 kiểu dữ liệu trong tất cả các file thực tế công việc của tôi là: Các dòng tổng lớn (ứng với I, II trong bài này) luôn nằm trên các dòng tổng nhỏ tức ô ngay dưới nó không phải ô trắng khác với các dòng tổng nhỏ ô liền dưới nó là ô trắng (rỗng).

.
Số I la mã thì khỏi cần bàn (nó nằm đầu tiên).
Vậy bạn nói cho mọi người biết làm cách nào để "nhận ra" được số II la mã
???
Sao bạn không tách chúng thành 2 cột cho dễ xử lý?
 
Upvote 0
Dấu hiệu để nhận diện chỉ ra được sự khác nhau của 2 kiểu dữ liệu trong tất cả các file thực tế công việc của tôi là: Các dòng tổng lớn (ứng với I, II trong bài này) luôn nằm trên các dòng tổng nhỏ tức ô ngay dưới nó không phải ô trắng khác với các dòng tổng nhỏ ô liền dưới nó là ô trắng (rỗng).

Bạn đang học về mảng thì OK, tuy nhiên, vọc chưa đúng cách cũng không tốt. Bạn cần đưa ra một file giả lập thôi, một bên là dữ liệu đầu vào và một bên là đầu ra (kết quả mong đợi của bạn), như vậy sẽ dễ dàng có định hướng cho bài của bạn hơn.
 
Upvote 0
Nói chung để code chạy thì bạn phải chỉ ra được sự khác nhau của 2 kiểu dữ liệu (ví dụ loại thứ nhất luôn là chữ I chẳng hạn) ---> Nếu không làm rõ được điều này và nay nhập vầy, mai lại nhập khác thì code nó biết đường đâu mà lần

II có đặc điểm là ô dưới nó có một số (cụ thể fle đính kèm là số 1), trong khi các dòng tổng nhỏ thì ô dưới nó là để trống.

(Vì đây là dữ liệu kế thừa của phòng nghiệp vụ khác, chương trình khác trong cơ quan sinh ra ah, chứ không phải do bản thân tự nhập).
 
Lần chỉnh sửa cuối:
Upvote 0
Dấu hiệu để nhận diện chỉ ra được sự khác nhau của 2 kiểu dữ liệu trong tất cả các file thực tế công việc của tôi là: Các dòng tổng lớn (ứng với I, II trong bài này) luôn nằm trên các dòng tổng nhỏ tức ô ngay dưới nó không phải ô trắng khác với các dòng tổng nhỏ ô liền dưới nó là ô trắng (rỗng).

Trong Code:
PHP:
Sub tinhtong()
Dim DL(), i As Long, Dongcuoi, Tmp, Congviec, Tong
Dongcuoi = [B65000].End(xlUp).Row
DL = Range("A8:B" & Dongcuoi).Value
For i = UBound(DL, 1) To 1 Step -1
If DL(i, 1) = "" Then
Tmp = Tmp + DL(i, 2)
ElseIf DL(i, 1) <> "" And DL(i - 1, 1) <> "" Then
DL(i, 2) = Tmp
Congviec = i
Tong = Tong + DL(Congviec, 2)
Tmp = 0
Else
DL(i, 2) = Tong
Tong = 0
End If
Next i
Range("A8:B" & Dongcuoi).Value = DL
End Sub
Nó có nhược điểm là ô trên cùng DL(i - 1, 1) = DL(0,1) nên bị lỗi, tôi chưa nghĩ ra cách nào để sửa cả.
Xin thày Ndu và mọi người gợi ý cho giải pháp để khắc phục.
Tôi thấy quả là tự mình làm mình thêm rắc rối, nếu tiêu đề tổng nhỏ a,b,c nằm 1 cột, tiêu đề tổng lớn I,II,III... nằm trên cột khác thì làm quá dễ dàng.
Quét từ dưới lên, gặp dòng tổng nhỏ thì tính tổng nhỏ, gặp dòng tổng lớn thì tính tổng lớn, mắc chi cho nó chung một cột rồi sinh ra lắm thứ số, text...
 
Upvote 0
II có đặc điểm là ô dưới nó có một số (cụ thể fle đính kèm là số 1), trong khi các dòng tổng nhỏ thì ô dưới nó là để trống.

(Vì đây là dữ liệu kế thừa của phòng nghiệp vụ khác, chương trình khác trong cơ quan sinh ra ah, chứ không phải do bản thân tự nhập).
Bạn đưa lại file lên đi...
Tôi kiểm tra trong file ở bài 224 thì thấy " ở dưới" thằng nào cũng có num cả
 
Upvote 0
Tôi xin gửi lại File lên, nhờ thày giúp cho (các ô cần tính bôi màu vàng)
 

File đính kèm

  • Tinh tong TP.xls
    16.5 KB · Đọc: 31
Lần chỉnh sửa cuối:
Upvote 0
Nhưng cách của bác Viethoai trong trường hợp này thì dòng I và II không chạy được.
Baitoan.jpg
 

File đính kèm

  • Tinh tong 2.xls
    17.5 KB · Đọc: 49
Upvote 0
Nhưng cách của bác Viethoai trong trường hợp này thì dòng I và II không chạy được.
Như bạn đã nói: dấu hiệu nhận ra thằng tổng "bự" là dưới nó phải có "cái gì đó", đúng không?
Vậy thì sửa lại tí:
PHP:
Sub tinhtong()
  Dim DL(), i As Long, Tmp1, Tmp2
  DL = Range([A8], [B65000].End(xlUp)).Value
  On Error Resume Next
  For i = UBound(DL, 1) To 1 Step -1
    If DL(i, 1) = "" Then
      Tmp1 = Tmp1 + DL(i, 2)
    ElseIf DL(i, 1) <> "" Then
      DL(i, 2) = Tmp1
      Tmp2 = Tmp2 + Tmp1
      Tmp1 = 0
      If DL(i + 1, 1) <> "" Then
        DL(i, 2) = Tmp2
        Tmp2 = 0
      End If
    End If
  Next i
  Range([A8], [B65000].End(xlUp)).Value = DL
End Sub
 
Upvote 0
Cảm ơn thày Ndu rất nhiều, chiều nghĩ mãi tôi đã làm gần như thày mà mãi không ra, nhờ Code của thày giảng bây giờ tôi đã hiểu được nguyên nhân rồi

PHP:
Sub tinhtong()
  Dim DL(), i As Long, Tmp1, Tmp2
  DL = Range([A8], [B65000].End(xlUp)).Value
  On Error Resume Next
  For i = UBound(DL, 1) To 1 Step -1
    If DL(i, 1) = "" Then
      Tmp1 = Tmp1 + DL(i, 2)
    ElseIf DL(i, 1) <> "" Then
      DL(i, 2) = Tmp1
      Tmp2 = Tmp2 + Tmp1
      Tmp1 = 0
      ElseIf DL(i + 1, 1) <> "" Then
                 DL(i, 2) = Tmp2
        Tmp2 = 0
          End If
  Next i
  Range([A8], [B65000].End(xlUp)).Value = DL
End Sub
---------------------

Hóa ra nó khác nhau (trước tôi cứ tưởng giống nhau), của thày If sau đè, thay thế If trước vì 2 thằng If này bình đẳng vai trò, đẳng cấp bằng nhau;

Cách làm trước của tôi dùng ElseIf nên teo, thằng sau "không dám thay" thằng trước do nó là cấp dưới nên sợ cấp trên.

Chúc thày luôn mạnh khỏe, hạnh phúc.
 
Lần chỉnh sửa cuối:
Upvote 0
Thời gian này rỗi tôi đang cố gắng nghiên cứu về Dictionary, hôm nọ tôi đã được các thày lọc giúp một bài mẫu, hôm nay ngồi nghiên cứu tôi thử làm
Bài toán: Lọc các giá trị duy nhất của cột A ra cột B

PHP:
Sub locDic()
  Dim KQ(), DL(), i As Long, Dic As Object
  Set Dic = CreateObject("Scripting.Dictionary")
  dongcuoi = [A65000].End(xlUp).Row
  DL = Range("A1:A" & dongcuoi).Value
 Range("B:B").Clear
  ReDim KQ(1 To UBound(DL, 1), 1 To 1)
  For i = 1 To UBound(DL)
        If DL(i, 1) <> "" And Not Dic.Exists(DL(i, 1)) Then
        j = j + 1
        Dic.Add DL(i, 1), j
        KQ(j, 1) = DL(i, 1)
          End If
  Next
  Range("B1").Resize(j) = KQ
End Sub
Nhưng tôi vẫn lăn tăn (j) ở đoạn Dic.Add DL(i, 1), j chẳng có nghĩa gì? Tức Item trong trường hợp này không cần thiết?

Không biết sư phụ Ptm0412 hôm nay đi đâu mà không thấy vào diễn đàn; hôm nào thày mắng, nhắc nhở nhiều thì mình phải cố gắng hơn nữa.
 
Lần chỉnh sửa cuối:
Upvote 0
Xin làm phiền mọi người một chút, thời gian này rỗi tôi đang cố gắng nghiên cứu về Dictionary, hôm nọ tôi đã được các thày lọc giúp một bài mẫu, hôm nay ngồi nghiên cứu tôi thử làm thuật toán khác đi một chút xem có được không.

Bài toán: Lọc duy nhất những giá trị của cột A ra cột B

PHP:
Sub Loc()
Dim DL(), i As Long, Dongcuoi As Long, Dic As Object
Dongcuoi = [A65000].End(xlUp).Row
DL = Range("A1:A" & Dongcuoi).Value
ReDim KQ(1 To UBound(DL, 1), 1 To 1)
With CreateObject("Scripting.Dictionary")
For i = 1 To UBound(DL, 1)
If DL(i, 1) <> "" And Not Dic.exists(DL(i, 1)) Then
j = j + 1
Dic.Add DL(i, 1), j
KQ(j, 1) = DL(i, 1)
End If
Next
End With
[B1].Resize(j, 1).Value = KQ
End Sub

Xin chỉ dùm Code trên thiếu cái gì mà chạy chưa được.

Không biết sư phụ Ptm0412 hôm nay đi đâu mà không thấy vào diễn đàn; hôm nào thày mắng, nhắc nhở nhiều thì mình phải cố gắng hơn nữa.
Bạn đã khai báo Dic as Object nhưng chẳng có động tác Set nó bằng cái gì cả nên lỗi là phải rồi
Vậy bạn có 2 lựa chọn
1> Dùng biến Dic và Set nó thành Dictionary
PHP:
Sub Loc()
  Dim DL(), i As Long, Dic As Object, j As Long
  DL = Range([A1], [A65000].End(xlUp)).Value
  ReDim KQ(1 To UBound(DL, 1), 1 To 1)
  Set Dic = CreateObject("Scripting.Dictionary")
  For i = 1 To UBound(DL, 1)
    If DL(i, 1) <> "" And Not Dic.Exists(DL(i, 1)) Then
      j = j + 1
      Dic.Add DL(i, 1), j
      KQ(j, 1) = DL(i, 1)
    End If
  Next
  [B1].Resize(j, 1).Value = KQ
End Sub
2> Dùng With... End With và khỏi cần biến Dic (Vì Dictionary ở trong With.. End With rồi)
PHP:
Sub Loc()
  Dim DL(), i As Long, j As Long
  DL = Range([A1], [A65000].End(xlUp)).Value
  ReDim KQ(1 To UBound(DL, 1), 1 To 1)
  With CreateObject("Scripting.Dictionary")
    For i = 1 To UBound(DL, 1)
      If DL(i, 1) <> "" And Not .Exists(DL(i, 1)) Then
        j = j + 1
        .Add DL(i, 1), j
        KQ(j, 1) = DL(i, 1)
      End If
    Next
  End With
  [B1].Resize(j, 1).Value = KQ
End Sub
Nói chung thuật toán là vậy nhưng khi áp dụng nên phòng những lỗi có thể xảy ra, chẳng hạn vùng cột A chẳng có dữ liệu nào nên j sẽ = 0 (không tạo được mảng KQ)
Ngoài ra, thay vì IF và AND, nên chia thành 2 IF... Tức loại trừ từ từ, như thế tốc độ sẽ nhanh hơn (thay vì luôn phải xét 2 đk cùng lúc)
Cuối cùng, dù rằng không còn nghĩ ra được còn lỗi gì có thể xảy ra cũng nên cho câu bẫy lỗi đầu code (phòng những sự cố ngoài ý muốn)
Tôi sẽ làm như sau:
PHP:
Sub Loc()
  Dim DL(), i As Long, j As Long, tmp As String
  On Error GoTo ExitSub ''<-- Bay loi phuong ngua
  DL = Range([A1], [A65000].End(xlUp)).Value
  ReDim KQ(1 To UBound(DL, 1), 1 To 1)
  With CreateObject("Scripting.Dictionary")
    For i = 1 To UBound(DL, 1)
      If CStr(DL(i, 1)) <> "" Then ''<-- Dùng 2 lan IF theo phuong phap loai tru, toc do se nhanh hon
        tmp = CStr(DL(i, 1))
        If Not .Exists(tmp) Then
          j = j + 1
          .Add tmp, j
          KQ(j, 1) = tmp
        End If
      End If
    Next
  End With
  If j > 0 Then Range("B1").Resize(j, 1).Value = KQ ''<-- IF cho nay de kiem tra xem mang da duoc tao hay chua?
ExitSub:
End Sub
 
Upvote 0
Trước kia do chưa biết từ lập trình là gì, những bài đầu rất lúng túng (cả về thuật toán và cú pháp), nhờ những kiến thức quý báu của các thày chỉ dạy đến nay tôi cảm thấy đã bắt đầu dễ dàng hơn khi thực hành (nếu so sánh với chính bản thân tôi cách đây khoảng 1 tháng thì đúng là tốt lên rất nhiều), dĩ nhiên nhiều khi vẫn chưa đi đến kết quả cuối cùng nhưng những điểm sai đã phần nào ít hơn, đã dần hiểu hơn bản chất các đối tượng, hướng giải quyết bài toán đã rõ ràng hơn.

Quả thật không biết phải nói lời cảm ơn của mình thế nào đối với các thày, mọi người trên diễn đàn. Xin cảm tạ rất nhiều

-----------------------
Xin thắc mắc 1 chút: Trong bài toán này hình như thành phần Item trong cú pháp Dic.Add Key, Item không có nhiều ý nghĩa lắm thì phải, vì tôi thấy cái .Add tmp, j (thì j có vẻ hơi thừa?) bởi thay j bằng cái gì cũng được (vì đã có j = j+1 ở trên rồi)
 
Lần chỉnh sửa cuối:
Upvote 0
Xin thắc mắc 1 chút: Trong bài toán này hình như thành phần Item trong cú pháp Dic.Add Key, Item không có nhiều ý nghĩa lắm thì phải, vì tôi thấy cái .Add tmp, j (thì j có vẻ hơi thừa?) bởi thay j bằng cái gì cũng được (vì đã có j = j+1 ở trên rồi)
Vì trong bài này bạn không dùng đến nên nó xem như là thừa nên có thể sửa thành Dic.Add tmp, "" (tức không xài Item)
Rất nhiều bài toán mà việc xài Item trở nên rất hiệu quả... Dùng nó để "đánh dấu vị trí" hoặc lọc duy nhất và cộng dồn chẳng hạn...
Nói chung, công cụ là thế, xài thế nào là việc của ta
 
Upvote 0
Web KT
Back
Top Bottom