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,600
Được thích
2,907
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ị
 
Đó là nhiệm vụ của một cái từ khoá tên là Dim
Dim X(1 to 1000)
Khi ấy:
X(1) là cái X001 mà bạn muốn
X(1000) là cái X1000
 
Upvote 0
Đó là nhiệm vụ của một cái từ khoá tên là Dim
Dim X(1 to 1000)
Khi ấy:
X(1) là cái X001 mà bạn muốn
X(1000) là cái X1000


Ah cảm ơn bạn nhiều
Mình thường sử dụng nhiều với ma trận. Dim như vậy thì tạo dimension cho nó thế nào bạn.
Ví dụ
- X(1) size(2x2)
- X(2) size(4x5)
- etc.

Tại vì mỗi biến X(i) thì size thay đổi (mxn) nên mình lại đang kẹt vụ này
Mình thử
Dim X(1 to 10)
Redim X(1,2,2)
Redim X(2,5,6)
etc
Thì VBA báo sai :(
 
Upvote 0
Ah cảm ơn bạn nhiều
Mình thường sử dụng nhiều với ma trận. Dim như vậy thì tạo dimension cho nó thế nào bạn.
Ví dụ
- X(1) size(2x2)
- X(2) size(4x5)
- etc.

Tại vì mỗi biến X(i) thì size thay đổi (mxn) nên mình lại đang kẹt vụ này
Mình thử
Dim X(1 to 10)
Redim X(1,2,2)
Redim X(2,5,6)
etc
Thì VBA báo sai :(
Dim X(1 to 10)
dim a(2,2)
x(1)=a
dim a(5,6)
X(2)=a
etc
 
Upvote 0
Ah cảm ơn bạn nhiều
Mình thường sử dụng nhiều với ma trận. Dim như vậy thì tạo dimension cho nó thế nào bạn.
Ví dụ
- X(1) size(2x2)
- X(2) size(4x5)
- etc.

Tại vì mỗi biến X(i) thì size thay đổi (mxn) nên mình lại đang kẹt vụ này
Mình thử
Dim X(1 to 10)
Redim X(1,2,2)
Redim X(2,5,6)
etc
Thì VBA báo sai :(
Tiếng Việt, cái đó không phải là ma trận.
Tôi có yêu cầu rằng nếu bạn giỏi tiếng Anh hơn tiếng Việt thì dùng thẳng tiếng Anh, tôi trả lời dễ hơn.
Tiếng Anh, cái đó gọi là jagged array; nếu dịch ra tiếng Việt thì là mảng răng cưa (không đều).
VBA thể hiện dạng này theo cấu trúc mảng trong mảng.
Đây là lần cuối tôi trả lời cho câu hỏi nửa Tây nửa Ta.
 
Upvote 0
Tiếng Việt, cái đó không phải là ma trận.
Tôi có yêu cầu rằng nếu bạn giỏi tiếng Anh hơn tiếng Việt thì dùng thẳng tiếng Anh, tôi trả lời dễ hơn.
Tiếng Anh, cái đó gọi là jagged array; nếu dịch ra tiếng Việt thì là mảng răng cưa (không đều).
VBA thể hiện dạng này theo cấu trúc mảng trong mảng.
Đây là lần cuối tôi trả lời cho câu hỏi nửa Tây nửa Ta.

Cảm ơn bạn nhiều
Nếu cách mình diển đạt làm phiền bạn thì mình xin lỗi bạn nhiều. Nhưng mà bạn ơi, trình độ mình có hạn. Lúc diễn đạt thì mình diển đạt theo cái mà mình biết và mình hiểu. Nêu đã biết tên gọi đúng cái đó là mảng răng cưa như bạn nói thì mình cũng ko phải diển đạt lòng vòng vậy đâu.
 
Upvote 0
Dim X(1 to 10)
dim a(2,2)
x(1)=a
dim a(5,6)
X(2)=a
etc
Đây là nhiệm vụ của cái tên biến mà các bạn vẫn hay dùng: tmp, tem, temp
Dim X(1 to ...), tmp ' nếu dùng tên tmpArr thì có thể khai luôn là tmpArr() để ngừoi đọc hiểu ngay nó phải luôn là Array
Redim tmp(1 to 100)
X(1) = tmp
...
 
Upvote 0
VBA thể hiện dạng này theo cấu trúc mảng trong mảng.
Giả sử cháu có một mảng tượng trưng cho các lớp học của một trường học nào đó, trong mỗi lớp học có các học sinh. Ví dụ như mangLopHocs(1)(2) là tên học sinh ở vị trí thứ 2 của lớp học 1 ( xét trong điều kiện tất cả đều là mảng một chiều). Cho cháu hỏi là nếu giờ cháu muốn duyệt các học sinh của một lớp nào đó thì phương án:
1, duyệt theo kiểu mangLopHocs(1)(x), với x là chỉ số.
2, gán mangLopHocs(1) vào một mảng nào đó rồi duyệt như bình thường.
Thì phương án 1 hay 2 sẽ nhanh và thuật tiện hơn.
Nếu bây giờ muốn thêm hoặc xóa một học sinh ( ý là định cỡ lại mảng danh sách học sinh) thì làm thế nào?
 
Upvote 0
Tôi không hiểu lắm yêu cầu của bạn. Mảng răng cưa chỉ dùng khi các phần tử không giống nhau. Tổ chức lớp học và học sinh thì đồng bộ.
Nếu tôi đoán không lầm thì cái bạn muốn cần phải dùng mảng 3 chiều:
Chiều 1 = lớp
Chiều 2 = học sinh
Chiều 3 = chi tiết học sinh
Ví dụ:
mangLopHS(1, 2, 1) = "Nguyễn Văn A"
mangLopHS(1, 2, 2) = 2010
mangLopHS(1, 2, 3) = ...
Đọc ra là "gán tên Nguyễn Văn A và năm sinh 2010 cho em học sinh thứ 2 trong lớp thứ nhất"
Đương nhiên với cấu trúc này, bạn phải có thêm một mảng Lop() cho biết chi tiết của lớp 1, 2, ...

Tuy nhiên, đó là cách thiết kế cấu trúc cổ điển, vì là mảng cho nên lúc xoá, bạn chỉ có thể xoá rồi dồn lên. Lúc thêm thì cũng vậy. Và vì vậy cho nên bạn phải đặt độ lớn của mảng trước.
Cách dễ hơn hết là dùng collection.

Nếu sẵn sàng dùng .NET thì có thể dùng các loại mảng động như ArrayList.

Cách thiết kế tường minh hơn 1 chút là dùng type
Type HocSinh
ten As String
namSinh As Integer
...
End Type
...
Dim mangLopHS() As HocSinh
mangLopHS(1).ten = "Nguyễn Văn A"
mangLopHS(1).namSinh = 2010
mangLopHS(1)... = ...

Và nếu bạn chịu khó cốt kiếc chút nữa thì có thể dùng Class.
 
Upvote 0
Tôi không hiểu lắm yêu cầu của bạn. Mảng răng cưa chỉ dùng khi các phần tử không giống nhau. Tổ chức lớp học và học sinh thì đồng bộ.
Nếu tôi đoán không lầm thì cái bạn muốn cần phải dùng mảng 3 chiều:
Chiều 1 = lớp
Chiều 2 = học sinh
Chiều 3 = chi tiết học sinh
Ví dụ:
mangLopHS(1, 2, 1) = "Nguyễn Văn A"
mangLopHS(1, 2, 2) = 2010
mangLopHS(1, 2, 3) = ...
Đọc ra là "gán tên Nguyễn Văn A và năm sinh 2010 cho em học sinh thứ 2 trong lớp thứ nhất"
Đương nhiên với cấu trúc này, bạn phải có thêm một mảng Lop() cho biết chi tiết của lớp 1, 2, ...

Tuy nhiên, đó là cách thiết kế cấu trúc cổ điển, vì là mảng cho nên lúc xoá, bạn chỉ có thể xoá rồi dồn lên. Lúc thêm thì cũng vậy. Và vì vậy cho nên bạn phải đặt độ lớn của mảng trước.
Cách dễ hơn hết là dùng collection.

Nếu sẵn sàng dùng .NET thì có thể dùng các loại mảng động như ArrayList.

Cách thiết kế tường minh hơn 1 chút là dùng type
Type HocSinh
ten As String
namSinh As Integer
...
End Type
...
Dim mangLopHS() As HocSinh
mangLopHS(1).ten = "Nguyễn Văn A"
mangLopHS(1).namSinh = 2010
mangLopHS(1)... = ...

Và nếu bạn chịu khó cốt kiếc chút nữa thì có thể dùng Class.

Dùng cái Type thì code sáng sủa, đỡ mắc viết nhầm.

Nêu ra vấn đề học sinh cho bác dễ tưởng tượng thôi, chứ cháu đang muốn hỏi liên quan tới kỹ thuật dùng mảng trong mảng, xem quá trình đọc viết các dữ liệu trong mảng con, cũng như quá trình thao tác mảng con ( ví dụ như redim, erase...)

Ps: Mảng con là cái mảng nằm trong mảng cha, mangLopHS(1) là mảng con của mảng mangLopHS.
 
Upvote 0
Dùng cái Type thì code sáng sủa, đỡ mắc viết nhầm.

Nêu ra vấn đề học sinh cho bác dễ tưởng tượng thôi, chứ cháu đang muốn hỏi liên quan tới kỹ thuật dùng mảng trong mảng, xem quá trình đọc viết các dữ liệu trong mảng con, cũng như quá trình thao tác mảng con ( ví dụ như redim, erase...)

Ps: Mảng con là cái mảng nằm trong mảng cha, mangLopHS(1) là mảng con của mảng mangLopHS.
Nếu là ngôn ngữ khác thì ngừoi ta đã dùng danh sách kết nối (linked list). Tuy nhiên, VBA không có dạng cấu trúc này cho nên dùng mảng khá luộm thuộm.
Nên nhớ rằng ưu điểm của mảng là dãy liền kề nhau khiến cho việc truy cập cũng như lô gic truy cập rất hiệu quả. Mặt khác nó cũng là khuyết điểm vì nó khiến cho việc thêm bớt phần tử rất rối rắm.
Dữ liệu "Liền kề nhau" được thể hiện theo dạng mà tiếng nghề gọi là "sequential".

Theo như yêu cầu của bạn, chúng ta THỬ VÍ DỤ rằng bắt buộc phải thiết kế theo cấu trúc mảng, và không muốn kiểu đơn giản mảng nhiều chiều. Lúc ấy cách thiết kế của tôi sẽ như vầy:
- Đặt một mảng LopHoc(0 To soLopHoc); soLopHoc là số lớp học.
- Mảng này có phần tử đầu tiên, LopHoc(0), là một mảng chi tiết các lớp học. LopHoc(0) được Dim là (1 To soLopHoc). Phần tử i liên quan đến lớp học i. Ví dụ LopHoc(0)(1) chứa chi tiết lớp học 1.
- Với i > 0 thì phần tử LopHoc(i) là mảng chứa học sinh. LopHoc(i)(j) là học sinh j trong lớp i.
Theo cấu trúc này thì bạn có thể dùng sequential cho lớp học. Mỗi lần thêm thì thêm HS ở cuối và mõi lần xoá thì dồn lên. Cả hai đều có thể Redim Preserved mảng.

Nếu dùng dạng mảng 3 chiều (hay nhiều chiều hơn) như tôi nói ở bài trước thì bạn không thể Redim Preserved mảng, và bắt buộc phải đặt trước kích cỡ của mảng lớn hơn dự định dùng. Với cách này, bạn nên có một mảng song với với mảng kia để cho biết mỗi chiều đã sử dụng đến bao nhiêu phần tử.
 
Upvote 0
Lúc đó mình copy nội dung mạng con ra một mảng khác, sau đó redim Preserved và cuối cùng là ghi lại mảng đó vào mảng cũ?
Thì cứ vậy, mấy tầng thì làm đủ bấy tầng. Nếu muốn thực hiện thì tốt hơn hết nên viết một hàm/sub chuyên làm công việc chép và redim. Tuy nó không làm công việc hiệu quả hơn nhưng ít nhất cũng giúp cho code dễ đọc hơn.
Tôi có nói là cấu trúc mảng không thích hợp với ví dụ này mờ.
 
Upvote 0
Xin chào các bạn,
OT muốn so sánh dữ liệu trong từ cột A:E trong 2 sheets("old") và sheets("new") và trả về kết quả khác nhau tại cột E sheets("Results")
Đoạn code dưới đây OT sưu tầm chỉ so sánh được cột A, mong các bạn sửa giúp trường hợp so sánh A:E ạ.
Mã:
Option Explicit
Sub NoMatches()
    'https://www.thesmallman.com/compare-two-worksheets
    Dim dic As Object, ar As Variant, ar1 As Variant
    Dim var As Variant, i As Long, n As Long
    Dim shCu As Worksheet, shMoi As Worksheet, shKQ As Worksheet
   
    Set shCu = ThisWorkbook.Worksheets("OLD")
    Set shMoi = ThisWorkbook.Worksheets("NEW")
    Set shKQ = ThisWorkbook.Worksheets("Results")
   
    Set dic = CreateObject("Scripting.Dictionary")
    dic.CompareMode = 1
    ar = shCu.Range("A2", shCuRange("A" & Rows.Count).End(xlUp)).Value
    var = shMoi.Range("A2", shMoi.Range("A" & Rows.Count).End(xlUp)).Value
    ReDim ar1(1 To UBound(var), 1 To 1)
    For i = 1 To UBound(ar)
        If Not dic.exists(ar(i, 1)) Then
            dic.Add ar(i, 1), ar(i, 1)
        End If
    Next i
    For i = 1 To UBound(var)
        If Not dic.exists(var(i, 1)) Then
            n = n + 1
            ar1(n, 1) = var(i, 1)
        End If
    Next i
   
    shKQ.Range("E2:E" & UBound(var)).Value = ar1
    shKQ.Range("E2:E" & UBound(var)).RemoveDuplicates 1
   
End Sub
 
Upvote 0
Xin chào các bạn,
OT muốn so sánh dữ liệu trong từ cột A:E trong 2 sheets("old") và sheets("new") và trả về kết quả khác nhau tại cột E sheets("Results")
Đoạn code dưới đây OT sưu tầm chỉ so sánh được cột A, mong các bạn sửa giúp trường hợp so sánh A:E ạ.
Mã:
Option Explicit
Sub NoMatches()
    'https://www.thesmallman.com/compare-two-worksheets
    Dim dic As Object, ar As Variant, ar1 As Variant
    Dim var As Variant, i As Long, n As Long
    Dim shCu As Worksheet, shMoi As Worksheet, shKQ As Worksheet
  
    Set shCu = ThisWorkbook.Worksheets("OLD")
    Set shMoi = ThisWorkbook.Worksheets("NEW")
    Set shKQ = ThisWorkbook.Worksheets("Results")
  
    Set dic = CreateObject("Scripting.Dictionary")
    dic.CompareMode = 1
    ar = shCu.Range("A2", shCuRange("A" & Rows.Count).End(xlUp)).Value
    var = shMoi.Range("A2", shMoi.Range("A" & Rows.Count).End(xlUp)).Value
    ReDim ar1(1 To UBound(var), 1 To 1)
    For i = 1 To UBound(ar)
        If Not dic.exists(ar(i, 1)) Then
            dic.Add ar(i, 1), ar(i, 1)
        End If
    Next i
    For i = 1 To UBound(var)
        If Not dic.exists(var(i, 1)) Then
            n = n + 1
            ar1(n, 1) = var(i, 1)
        End If
    Next i
  
    shKQ.Range("E2:E" & UBound(var)).Value = ar1
    shKQ.Range("E2:E" & UBound(var)).RemoveDuplicates 1
  
End Sub
Đọc code rồi "mơ màng" ra kết quả.
Sao kiểm chứng được "đúng sai là sự thật"?
 
Upvote 0
Con chào Thầy ạ,
Cảm ơn Thầy đã đã quan tâm ạ, con gửi file kèm nhờ Thầy và mọi người xem giúp ạ.
Vẫn mơ hồ.
- 2 sheet xét theo từng dòng từ cột A đến E?
- Nếu từng Cell có giá trị của 2 sheet khác nhau thì "tô màu", vậy nội dung trong cell kết quả ghi nội dung của sheet 1 hay sheet2?
- Cũng giải thích rõ kết quả trong sheet Result: E2, G2, I2 làm sao mà có? Quy luật là sao?
 
Upvote 0
Vẫn mơ hồ.
- 2 sheet xét theo từng dòng từ cột A đến E?
- Nếu từng Cell có giá trị của 2 sheet khác nhau thì "tô màu", vậy nội dung trong cell kết quả ghi nội dung của sheet 1 hay sheet2?
- Cũng giải thích rõ kết quả trong sheet Result: E2, G2, I2 làm sao mà có? Quy luật là sao?
À đúng rồi, con hiểu rồi.
Nghĩa là thế này Thầy ạ, đúng là con mô tả sai không đúng mục đích. Con gửi lại file và xin phép xóa file kèm bài 1317 ạ
Lọc duy nhất A,B,C,D,E so sánh 2 sheet nếu khác nhau trả về kết quả ạ..( cột F ở 2 sheet là cột phụ minh họa), mong muốn code khác không phải sử dụng cột phụ F.
Và cuối cùng là lọc duy nhất kết quả khác nhau để trả về những giá trị duy nhất trong 1 cột E sheets("Results")
không sử dụng RemoveDuplicates mà cũng ra như kết quả như file kèm ạ.
Cảm ơn Thầy nhiều ạ

Sửa bổ sung: không sử dụng RemoveDuplicates (mất định dạng)
 

File đính kèm

  • So sanh 2 Sheet.xlsm
    23.4 KB · Đọc: 35
Lần chỉnh sửa cuối:
Upvote 0
À đúng rồi, con hiểu rồi.
Nghĩa là thế này Thầy ạ, đúng là con mô tả sai không đúng mục đích. Con gửi lại file và xin phép xóa file kèm bài 1317 ạ
Lọc duy nhất A,B,C,D,E so sánh 2 sheet nếu khác nhau trả về kết quả ạ..( cột F ở 2 sheet là cột phụ minh họa), mong muốn code khác không phải sử dụng cột phụ F.
Và cuối cùng là lọc duy nhất kết quả khác nhau để trả về những giá trị duy nhất trong 1 cột E sheets("Results")
không sử dụng RemoveDuplicates mà cũng ra như kết quả như file kèm ạ.
Cảm ơn Thầy nhiều ạ

Sửa bổ sung: không sử dụng RemoveDuplicates (mất định dạng)
Biết xài "Dic" thì cứ "Dic" mà "quất".
PHP:
Public Sub Gpe()
Dim Dic As Object, sArr(), dArr(), I As Long, J As Long, K As Long, R As Long, Txt As String
Set Dic = CreateObject("Scripting.Dictionary")
    '===================================='
    sArr = Sheets("OLD").Range("A2", Sheets("OLD").Range("A2").End(xlDown)).Resize(, 5).Value
    R = UBound(sArr)
    For I = 1 To R
        Txt = Space(0)
        For J = 1 To 5
            Txt = Txt & sArr(I, J)
        Next J
        Dic.Item(Txt) = ""
    Next I
    '===================================='
    sArr = Sheets("NEW").Range("A2", Sheets("NEW").Range("A2").End(xlDown)).Resize(, 5).Value
    R = UBound(sArr)
    ReDim dArr(1 To R, 1 To 1)
    For I = 1 To R
        Txt = Space(0)
        For J = 1 To 5
            Txt = Txt & sArr(I, J)
        Next J
        If Not Dic.Exists(Txt) Then
            Dic.Item(Txt) = ""
            K = K + 1
            dArr(K, 1) = Txt
        End If
    Next I
    '===================================='
Sheets("Results").Range("E2").Resize(1000).ClearContents
Sheets("Results").Range("E2").Resize(K) = dArr
Set Dic = Nothing
End Sub
 
Upvote 0
Web KT
Back
Top Bottom