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ị
 
nhờ MOD xóa bài này, bị trùng , mạng 3G của tôi bị nghẽn, hic
 
Lần chỉnh sửa cuối:
Upvote 0
Rắc rối quá nhỉ, thế để cho tổng quát ban đầu sao mình không cho nó lớn hết cỡ đi ví dụ
ReDim KQ(1 to 65536, 1 to 1) chẳng hạn, lúc đó sẽ chẳng cần quan tâm đến cái anh Arr làm chi.

Đã mất công xây dựng câu lệnh này :
Arr = Range([A1], [A65000].End(xlUp)).Value
Thì sao lại bắt cái KQ() chứa nhiều thế (mà chẳng để làm gì) dù mảng có vô địch về tốc độ thì cũng khổ thân cái máy tính bạn ạ.
 
Lần chỉnh sửa cuối:
Upvote 0
Làm vậy cũng được mà nó sẽ tốn bộ nhớ máy tính bạn ah khi làm việc sẽ chậm hơn

Không chỉ tốn bộ nhớ không đâu, mà còn xảy ra chuyện 65 ngàn dòng vẫn thiếu đấy. Thí dụ lọc danh sách từ 2 hoặc nhiều cột thành một, mỗi cột 40 ngàn dòng là toi.

Cho nên vấn đề của ReDim là ở chỗ tính toán con số tương đối chính xác, dư 1 chút còn hơn thiếu, nhưng không phải quá dư để tốn bộ nhớ.
 
Upvote 0
Tôi đang từng bước tự làm các bài tập về mảng, tôi đang định tính tổng các thành phần cột B theo số thứ tự cột A nhưng chạy Code lại không được, xin hãy chỉ giúp tôi sửa lại cho đúng
PHP:
Sub btoan() Dim DL(), i As Long, Tmp 
DL = Range([B1], [B65000].End(xlUp)).Value 
ReDim Arr(1 To UBound(DL, 1), 1 To 2) 
For i = UBound(DL, 1) To 1 Step -1 
If Arr(i, 1) = "" Then 
Tmp = Arr(i, 2) + Tmp
 Else: Arr(i, 2).Value = Tmp 
Tmp = 0 
End If 
Next i
Range("B1").Resize(UBound(DL, 1), 1).Value = Arr 
End Sub

Trong file đính kèm tính tổng điền vào cột B (trong trường hợp này là ô B1 và ô B6)
 

File đính kèm

  • Tinh tong.xlsx
    8.2 KB · Đọc: 65
Lần chỉnh sửa cuối:
Upvote 0
Tôi đang từng bước tự làm các bài tập về mảng, tôi đang định tính tổng các thành phần cột B theo số thứ tự cột A nhưng chạy Code lại không được, xin hãy chỉ giúp tôi sửa lại cho đúng
PHP:
Sub btoan()
Dim DL(), i As Long, Tmp
DL = Range([B1], [B65000].End(xlUp)).Value
ReDim Arr(1 To UBound(DL, 1), 1 To 2)
For i = UBound(DL, 1) To 1 Step -1
If Arr(i, 1) = "" Then
Tmp = Arr(i, 2) + Tmp
Else: Arr(i, 2).Value = Tmp
Tmp = 0
End If
Next i
Range("B1").Resize(UBound(DL, 1), 1).Value = Arr
End Sub

Bạn đưa cái File mẫu lên xem, tôi nhìn chẳng hiểu tẹo nào cả? "tính tổng các thành phần cột B theo số thứ tự cột A" là tính làm sao?
 
Upvote 0
- If Arr(i, 1) = "" Then
Arr vừa mới ReDim chứ chưa hề gán dữ liệu, thì i = bao nhiêu cũng trống rỗng

- Tmp = Arr(i, 2) + Tmp
Tmp chưa gán giá trị, nên cũng trống rỗng
Hai cái trống rỗng cộng nhau, may sao, bằng 0

- Else: Arr(i, 2).Value = Tmp
Dù cái Else này không bao giờ dùng tới, nhưng nếu dùng, Arr(i, 2) lại cũng bằng trống rỗng

- Tmp = 0
bây giờ thì có thể Tmp sẽ được gán giá trị 0, nếu như ...


Tóm lại, bước đầu phải là suy luận, bạn ạ. Bạn lấy dữ liệu từ cột B vào DL, còn Arr chả có gì hết, mà bạn toàn lấy từ Arr bỏ vào Arr, không hề đụng đến DL, thì làm sao mà ra kết quả?
 
Lần chỉnh sửa cuối:
Upvote 0
Thấy lạ ở dòng này nữa :
DL = Range([B1], [B65000].End(xlUp)).Value
ReDim Arr(1 To UBound(DL, 1), 1 To 2)

Cái chỗ bôi đỏ đó không biết để làm gì, đang xét mảng gồm 1 cột và nhiều dòng mà, thêm cái đó máy tính khổ!
Câu lệnh này ;
Range("B1").Resize(UBound(DL, 1), 1).Value = Arr

Xử lý xong ÚP luôn kết quả lên vùng dữ liệu đang xét à, nhỡ code sai thì sao mà kiểm tra kết quả có đúng không nhỉ???
 
Upvote 0
Xin thày gợi ý chút nữa, tôi đã cố gắng sửa gần đúng rồi nhưng bản thân không phát hiện ra chỗ sai là ở đâu.

PHP:
Sub btoan()
Dim DL(), Dongcuoi As Long, Tmp
Dongcuoi = [B65000].End(xlUp)
DL = Range("A1:B" & Dongcuoi).Value
For i = UBound(DL, 1) To 1 Step -1
If DL(i, 1) > 0 Then
DL(i, 2) = Tmp
Tmp = 0
 Else
 Tmp = DL(i, 2) + Tmp
End If
Next i
Range("A1").Resize(UBound(DL, 1), 2).Value = DL
End Sub
 
Upvote 0
Xin thày gợi ý chút nữa, tôi đã cố gắng sửa gần đúng rồi nhưng bản thân không phát hiện ra chỗ sai là ở đâu.

PHP:
Sub btoan()
Dim DL(), Dongcuoi As Long, Tmp
Dongcuoi = [B65000].End(xlUp)
DL = Range("A1:B" & Dongcuoi).Value
For i = UBound(DL, 1) To 1 Step -1
If DL(i, 1) > 0 Then
DL(i, 2) = Tmp
Tmp = 0
 Else
 Tmp = DL(i, 2) + Tmp
End If
Next i
Range("A1").Resize(UBound(DL, 1), 2).Value = DL
End Sub
Riêng câu lệnh này thôi :
Range("A1").Resize(UBound(DL, 1), 2).Value = DL
thì toàn bộ các câu lệnh ở trên bạn làm chẳng còn ý nghĩa gì nữa.
Bạn xử lý DL rồi gán vào Tmp xong đổ kết quả ra sheet lại đúng là DL thì còn chuyện gì để nói, he he!
Thế cái Tmp bạn khai báo ra để làm gì?
 
Upvote 0
Tôi cứ nghĩ thuật toán trên nếu tại cột A có số thứ tự thì cột B mới tính lại ( DL(i, 2) = Tmp), còn nếu không các ô khác cột B để nguyên.

Sau khi thực hiện xong lệnh For...Next thì Dl là mảng trong đó giá trị cột A như cũ, cột B ở những dòng cột A trống là như cũ, chỉ có những dòng A có số thứ tự thì giá trị B mới tính lại (tính tổng) chứ. Sau đó gán trở lại là đúng rồi chứ nhỉ?

Tmp khai báo có tính chất nó đi cộng dồn những giá trị những ô B dưới B rồi ném vào ô B (tương ứng cột A đánh số thứ tự).

Nếu có thể rất mong được mọi người sửa lại dùm Code để tôi có thể nhận ra cái sai của mình
 
Upvote 0
Tôi phát hiện ra chỗ sai rồi bác hoamattroicoi ah, hóa ra không phải sai ở thuật toán mà là sai ở dòng Dongcuoi = [B65000].End(xlUp),đúng ra nó phải là Dongcuoi = [B65000].End(xlUp).Row

PHP:
Sub TinhTong()
Dim Dongcuoi, i As Long, tmp As Double
Dim DL()
  Dongcuoi = [B65000].End(xlUp).Row
    DL = Range("A1:B" & Dongcuoi).Value
For i = UBound(DL) To 1 Step -1
  If DL(i, 1) > 0 Then
    DL(i, 2) = tmp
    tmp = 0
  Else
    tmp = tmp + DL(i, 2)
  End If
Next i
[A1].Resize(UBound(DL), 2) = DL
End Sub

--------------------

Híc nhưng tôi cũng chưa hiểu tại sao 2 dòng này
PHP:
Dongcuoi = [B65000].End(xlUp)
Dongcuoi = [B65000].End(xlUp).Row
chúng khác nhau như thế nào? Bởi lẽ tôi Test thử 2 đoạn Code này:

PHP:
Sub TinhTong()
Dim Dongcuoi, i As Long
  Dongcuoi = [B65000].End(xlUp).Row
     i = Dongcuoi
   MsgBox i
End Sub

cho kết quả 19 cả giống hệt kết quả của đoạn

PHP:
Sub TinhTong()
Dim Dongcuoi, i As Long
  Dongcuoi = [B65000].End(xlUp)
     i = Dongcuoi
   MsgBox i
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Dongcuoi = [B65000].End(xlUp)

Câu này có nghĩa là Dongcuoi = giá trị ô cuối cột B. Đúng ra là:

Dongcuoi = [B65000].End(xlUp).Row

Sau đó chạy thử, và so sánh kết quả và suy luận của mình, tự tìm ra điểm sai. Nếu vẫn không thấy, hỏi tiếp.
 
Upvote 0
Tôi phát hiện ra chỗ sai rồi bác hoamattroicoi ah, hóa ra không phải sai ở thuật toán mà là sai ở dòng Dongcuoi = [B65000].End(xlUp),đúng ra nó phải là Dongcuoi = [B65000].End(xlUp).Row


Test thử 2 đoạn Code này:

PHP:
Sub TinhTong()
Dim Dongcuoi, i As Long
  Dongcuoi = [B65000].End(xlUp).Row
     i = Dongcuoi
   MsgBox i
End Sub

cho kết quả 19 cả giống hệt kết quả của đoạn

PHP:
Sub TinhTong()
Dim Dongcuoi, i As Long
  Dongcuoi = [B65000].End(xlUp)
     i = Dongcuoi
   MsgBox i
End Sub

Đó bởi vì bạn điền giá trị cho cột B bằng 1, 2, 3, ... đến hết (19). Dòng 19 có giá trị 19. Giống nhau là phải.
 
Upvote 0
Hóa ra do số tôi đánh vào trùng hợp (ô B19 đánh luôn 19) làm ngộ nhận kết quả giống nhau.
Tức là 1 cái là bằng giá trị ô B19 (Dongcuoi = [B65000].End(xlUp)) , cái kia trả về số dòng của ô B19 (Dongcuoi = [B65000].End(xlUp).Row)

Vì mới tập làm, nên phải vừa viết vừa hình dung cách dùng của từng đối tượng trong VBA, cũng may có thày chỉ bảo nên mới vỡ lẽ ra được nhiều vấn đề.

Rất mong được thày giúp đỡ, chỉ bảo thêm

Đa tạ thày rất nhiều

---------------------
Tôi cứ thắc mắc bác hoamattroicoi bảo thuật toán của tôi chưa hợp lý, vậy có cách làm làm tối ưu không hả thày
 
Lần chỉnh sửa cuối:
Upvote 0
Nếu bài toán tính tổng cho nhiều cột thì thuật toán làm như thế nào?

Tôi thắc mắc giả sử cột tổng cần tính được mở rộng ra khoảng 15 cột (từ cột B đến cột P) chẳng hạn thì thuật toán phải là thế nào?

(Lẽ dĩ nhiên khi đã tính ra được cột B rồi thì chỉ việc Copy sang các cột khác thôi, tuy nhiên nếu dữ liệu lớn thì sẽ mất thời gian, chắc đưa vào Code tính luôn sẽ nhanh hơn)

------------
Nhưng nếu cách giải vẫn như bài cũ thì sẽ rất dài (nhiều dòng lệnh), phải đặt những 15 biến kiểu như Tmp? Xin hỏi cách nào thuật toán gọn nhất.
 

File đính kèm

  • Tinh tong.xls
    31.5 KB · Đọc: 49
Upvote 0
Tôi thắc mắc giả sử cột tổng cần tính được mở rộng ra khoảng 15 cột (từ cột B đến cột P) chẳng hạn thì thuật toán phải là thế nào?

(Lẽ dĩ nhiên khi đã tính ra được cột B rồi thì chỉ việc Copy sang các cột khác thôi, tuy nhiên nếu dữ liệu lớn thì sẽ mất thời gian, chắc đưa vào Code tính luôn sẽ nhanh hơn)

------------
Nhưng nếu cách giải vẫn như bài cũ thì sẽ rất dài (nhiều dòng lệnh), phải đặt những 15 biến kiểu như Tmp? Xin hỏi cách nào thuật toán gọn nhất.
Thử code này xem, mình cũng mới tập tành với cái mảng trong VBA
PHP:
Public Sub GPE()
Dim Arr(), Tong(), i As Long, y As Long
Arr = Range([B3], [P100].End(xlUp)).Value
ReDim Tong(1 To UBound(Arr, 1) + 1, 1 To UBound(Arr, 2))
For i = UBound(Arr, 1) To 1 Step -1
    For y = 1 To UBound(Arr, 2)
        If Arr(i, y) <> "" Then
            Tong(i, y) = Tong(i + 1, y) + Arr(i, y)
        Else
            Arr(i, y) = Tong(i + 1, y)
            Tong(i, y) = 0
        End If
    Next y
Next i
 Range([B3], [P100].End(xlUp)).Value = Arr
End Sub
 

File đính kèm

  • Tinh tong1.rar
    8.9 KB · Đọc: 102
Upvote 0
Sau khi tính toán ra được các công việc thứ tự các công việc là 1,2,3..., tôi muốn tổng hợp thêm theo nhóm nữa: Nhóm I (bao gồm các thành phần con là 1,2,3), nhưng ngồi từ sáng đến giờ không phát hiện ra Code sai ở đâu, xin nhờ mọi người giúp

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, 1)
Tmp = 0
Else
DL(i, 2) = Tong
Tong = 0
End If
Next i
Range("A8:B" & Dongcuoi).Value = DL
End Sub
 

File đính kèm

  • Tinh tong.xls
    22.5 KB · Đọc: 45
Upvote 0
Sau khi tính toán ra được các công việc thứ tự các công việc là 1,2,3..., tôi muốn tổng hợp thêm theo nhóm nữa: Nhóm I (bao gồm các thành phần con là 1,2,3), nhưng ngồi từ sáng đến giờ không phát hiện ra Code sai ở đâu, xin nhờ mọi người giúp

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, 1)
Tmp = 0
Else
DL(i, 2) = Tong
Tong = 0
End If
Next i
Range("A8:B" & Dongcuoi).Value = DL
End Sub
Mình nói sơ bạn tự sửa nhé:
1. Khi i=1 thì Dl(i-1,1)=??? báo lỗi
2. Trường hợp của ElseIf DL(i, 1) <> "" And DL(i - 1, 1) <> "" Then thì DL(i-1, 2) = Tmp chứ không phải DL(i, 2) = Tmp
3. Sau Else để làm gì? bỏ nó thử xem
PS: Bạn chú ý B14=133 chứ không phải như trong file bạn để test lại kết quả
Thân
 
Lần chỉnh sửa cuối:
Upvote 0
Mình nói sơ bạn tự sửa nhé:
1. Khi i=1 thì Dl(i-1,1)=??? báo lỗi
2. Trường hợp của ElseIf DL(i, 1) <> "" And DL(i - 1, 1) <> "" Then thì DL(i-1, 2) = Tmp chứ không phải DL(i, 2) = Tmp
Thân

1. Cái 1 thì đúng là cần phải tìm cách khắc phục sửa lại theo ý bác rồi.
2. Nhưng dòng 2 ý tôi muốn thể hiện đối việc nhỏ (1,2,3 chứ không phải là nhóm việc lớn I, II) thì DL(i, 2) = Tmp chứ sao lại là DL(i-1, 2) = Tmp?
 
Upvote 0
1. Cái 1 thì đúng là cần phải tìm cách khắc phục sửa lại theo ý bác rồi.
2. Nhưng dòng 2 ý tôi muốn thể hiện đối việc nhỏ (1,2,3 chứ không phải là nhóm việc lớn I, II) thì DL(i, 2) = Tmp chứ sao lại là DL(i-1, 2) = Tmp?
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
 
Upvote 0
Web KT
Back
Top Bottom