Hàm VBA thao tác với ma trận

Liên hệ QC

NguyenNgocSon

KEEP WALKING
Tham gia
4/4/08
Bài viết
280
Được thích
832
Nghề nghiệp
Ths. Cầu hầm
Mình có vấn đề thao tác với mảng như file
không biết có cách nào giải quyết vấn đề này ?
Thân !
 

File đính kèm

  • Thao tac mang.xls
    33.5 KB · Đọc: 53
Giải thích Code VBA

Ủa sao kỳ vậySơn, cộng 2ma trận mà không cộng thứ tự gì hết?
Lẽ ra A(m, n) + B(m, n) = C(m, n)
C(i, j) = A(i, j) + B(i, j) chứ?
Đúng rồi ạ. Thực ra là hàm em muốn viết ý tưởng như sau:
Giả sử có 2 ma trân A, B muốn đưa vào ma trận C theo các chỉ số tương ứng.Dùng hàm Matrix2:
+ Hàm Matrix2 đưa ma trận A vào ma trận C1 theo đúng chỉ số tương ứng
+ Hàm Matrix2 đưa ma trận B vào ma trận C2 theo đúng chỉ số tương ứng
+ Sau đó mới cộng tương ứng 2 ma trận trung gian này để ra ma trận C ( C=C2+C2) cần tính.
Do đó, e muốn hàm gộp các thao tác này thành một hàm thôi ạ.
Cụ thể như file này ạ.
Cám ơn bác quan tâm!
Thân.
 

File đính kèm

  • HamXulyMang(Cai tien).xls
    54 KB · Đọc: 6
Upvote 0
Té ra là qua 3 cái trung gian, và cộng 2 trong số đó:

A-> C1
A -> B -> C2
cuối cùng C1 + C2

Vậy thì làm vầy, kết quả gặp chuỗi thì nối, gặp số thì cộng:

PHP:
Function SumMatrix(SourceRng As Range, SourceColTitle As Range, ColTitle2 As Range, ColTitle3 As Range)
Dim TmpArrB(), TmpArrC1(), TmpArrC2(), TmpArr(), SArray()
Dim SColT(), ColT2(), ColT3()
SArray = SourceRng.Value
    SColT = SourceColTitle.Value
    ColT2 = ColTitle2.Value
    ColT3 = ColTitle3.Value
    ArrSize = SourceColTitle.Count
    ReDim TmpArr(1 To ArrSize, 1 To ArrSize)
    TmpArrC1 = Matrix(SArray, SColT, ColT3)
    TmpArrB = Matrix(SArray, SColT, ColT2)
    TmpArrC2 = Matrix(TmpArrB, ColT2, ColT3)
    For i = 1 To ArrSize
        For j = 1 To ArrSize
            TmpArr(i, j) = TmpArrC1(i, j) + TmpArrC2(i, j)
        Next
    Next
    SumMatrix = TmpArr
    
End Function

Còn Matrix2 đang có đầu vào là range, sửa lại để có thể nhận đầu vào là Array.

PHP:
Function Matrix(SArr, ColTitle1, ColTitle2)
Dim TmpArr(), RwTitle1, RwTitle2
SArrSize = UBound(SArr, 1)
ReDim TmpArr(1 To SArrSize, 1 To SArrSize)
RwTitle1 = Application.Transpose(ColTitle1)
RwTitle2 = Application.Transpose(ColTitle2)
For i = 1 To SArrSize
    For j = 1 To SArrSize
        For k = 1 To SArrSize
            If ColTitle1(1, k) = ColTitle2(1, i) Then
                For h = 1 To SArrSize
                    If RwTitle1(h, 1) = RwTitle2(j, 1) Then
                        TmpArr(j, i) = SArr(h, k): Exit For
                    End If
                Next
            Exit For
            End If
        Next
    Next
Next
Matrix = TmpArr
End Function
 

File đính kèm

  • SumArray.rar
    21.1 KB · Đọc: 10
Lần chỉnh sửa cuối:
Upvote 0
Té ra là qua 3 cái trung gian, và cộng 2 trong số đó:
A-> C1
A -> B -> C2
cuối cùng C1 + C2
Dạ, em cám ơn bác.
Thực ra vẫn nhầm ý thế này ạ:
A-> C1
B -> C2
cuối cùng mới là: C1 + C2
Như vậy đầu vào của hàm như sau: Function SumMatrix(MatranA,chisoA,MatranB,chisoB,Chisogoc) (Ma trận A và B độc lập chứ không phái A -> B)
mới đúng ạ !
 
Lần chỉnh sửa cuối:
Upvote 0
Mệt quá!
Xem mẫu trong file rõ ràng B = Matrix(A, chỉ số A,chỉ số B). Công thức nằm sờ sờ ra.
từ B mới ra C2
Còn C1 lấy trực tiếp từ A.
 
Lần chỉnh sửa cuối:
Upvote 0
Mệt quá!
Xem mẫu trong file rõ ràng B = Matrix(A, chỉ số A,chỉ số B). Công thức nằm sờ sờ ra.
từ B mới ra C2
Còn C1 lấy trực tiếp từ A.
Dạ, em xin lỗi a. Vì em ngại viêt các số của B nên mới lấy như vậy.
Dạng hàm: Function SumMatrix(MatranA,chisoA,MatranB,chisoB,Chisogoc) (Ma trận A và B độc lập chứ không phái A -> B)
Em cám ơn !
20-11 Chúc thầy luôn khỏe, công tác tốt !
 
Lần chỉnh sửa cuối:
Upvote 0
Lần chỉnh sửa cuối:
Upvote 0
Vậy tôi nếu cũng ngại viết code, sửa code thì sao?
Hiện giờ đang rất ngại phải nhận mấy lời chúc đó đó. Nhận rồi cũng như mắc nợ.
Dạ không sao ạ.Vì lỗi này là do em ạ (Lần sau em sẽ chú ý khi yêu cầu %#^#$ - thực ra nhầm quan điểm chút thôi ạ). Cám ơn thầy đã giúp đỡ. Em cám ơn rất nhiều !
Thân.
 
Upvote 0
Nợ trần ai:

PHP:
Function SumMatrix(SRng1 As Range, SColTitle1 As Range, SRng2 As Range, SColTitle2 As Range, RColTitle As Range)
'SRng = Source Range, SColTitle = Source Column Titlles'
'RColTitle = Result Column Titles'
Dim TmpArrC1(), TmpArrC2(), TmpArr(), SArray1(), SArray2()
Dim SColT1(), SColT2(), RColT()
  SArray1 = SRng1.Value
  SArray2 = SRng2.Value
    SColT1 = SColTitle1.Value
    SColT2 = SColTitle2.Value
    RColT = RColTitle.Value
    ArrSize = SColTitle1.Count
    ReDim TmpArr(1 To ArrSize, 1 To ArrSize)
    TmpArrC1 = Matrix(SArray1, SColT1, RColT)
    TmpArrC2 = Matrix(SArray2, SColT2, RColT)
    For i = 1 To ArrSize
        For j = 1 To ArrSize
            If (IsNumeric(TmpArrC1(i, j)) And IsNumeric(TmpArrC2(i, j))) Then
                TmpArr(i, j) = Val(TmpArrC1(i, j)) + Val(TmpArrC2(i, j))
            Else
                TmpArr(i, j) = TmpArrC1(i, j) & TmpArrC2(i, j)
            End If
        Next
    Next
    SumMatrix = TmpArr
    
End Function
 

File đính kèm

  • SumArray2.rar
    20 KB · Đọc: 14
Upvote 0
Em cám ơn thầy nhiều ạ. Em đã check thử nhưng có trường hợp sau thì báo lỗi !
(File đính kèm)
 

File đính kèm

  • Check ham SumMatrix.xls
    71 KB · Đọc: 7
Upvote 0
1. Sao không nói rõ là kết quả có thể khác kích thước với nguồn? Ban đầu làm theo kích thước khác nhau, sửa lại kích thước bằng nhau, bây giờ lại té ra lỗi do kích thước khác nhau!

2. Sao trong file để tồn tại 2 function trùng tên Matrix()? Xoá 1 cái đi hoặc đổi tên đi chứ

3. Sao lại đẻ ra chuyện 2 Title trùng nhau B3 và C3 như trong file? Nói trước, nếu trùng title trong nguồn hoặc title kết quả, hoặc trùng trong cả 2, là công sức trước nay vất đi hết, vì thuật toán phá sản.
 

File đính kèm

  • Check ham SumMatrix.rar
    16.9 KB · Đọc: 14
Upvote 0
3. Sao lại đẻ ra chuyện 2 Title trùng nhau B3 và C3 như trong file? Nói trước, nếu trùng title trong nguồn hoặc title kết quả, hoặc trùng trong cả 2, là công sức trước nay vất đi hết, vì thuật toán phá sản.
Khi em check mà trùng Title vẫn thấy kết quả đúng ?
Nhưng em muốn hỏi: mình có thể tạo hàm dạng mở được không ạ; nếu như đầu vào có n ma trận thì cú pháp hàm dạng như sau:
Function SumMatrix(MatranA,chisoA,...,Matrann,Chison,Chisochung) được không ạ
Em cám ơn !
 
Upvote 0
Khi em check mà trùng Title vẫn thấy kết quả đúng ?

Trùng làm sao mà đúng hết được? Title nguồn trùng nhưng Kết quả không lấy từ title trùng đó thì dĩ nhiên đúng.

Nói về trùng title, không trùng dữ liệu của title đó:

1. Trùng title nguồn:
Khi dò tìm, thuật toán hiện thời lấy dòng đầu hoặc cột đầu trong số các title trùng, dòng sau cột sau không xét tới. Vậy nếu muốn lấy dữ liệu của title sau, thì thuật toán bó tay.

2. Trùng title đích:
Nếu 2 title giống nhau sẽ cho kết quả giống nhau.
Ngoài ra giả sử title nguồn cũng trùng, và muốn đích 1 lấy nguồn 1, đích 2 lấy nguồn 2, ... thì cũng bó tay nốt

Nhưng em muốn hỏi: mình có thể tạo hàm dạng mở được không ạ; nếu như đầu vào có n ma trận thì cú pháp hàm dạng như sau:
Function SumMatrix(MatranA,chisoA,...,Matrann,Chison,Chisochung) được không ạ

Tôi hông biết, để cao thủ khác làm vậy.
 
Upvote 0
Em cám ơn thầy rất nhiều về vấn đề này
Chúc thầy luôn khoẻ !
 
Upvote 0
Bác ptm0412 có thể cho e hỏi đoạn code nào có thể làm được việc sau:
PHP:
Public Function Matran(E As Double, A As Double, J As Double, l As Double)
Dim MT(1 To 6, 1 To 6)
Dim t1, t2, t3, t4, t5 As Double
t1 = E * A / l: t2 = 12 * E * J / (l ^ 3): t3 = 6 * E * J / (l ^ 2): t4 = 4 * E * J / l: t5 = 2 * E * J / l
MT(1, 1) = t1:  MT(1, 2) = 0:   MT(1, 3) = 0:   MT(1, 4) = -t1: MT(1, 5) = 0:   MT(1, 6) = 0
MT(2, 1) = 0:   MT(2, 2) = t2:  MT(2, 3) = t3:  MT(2, 4) = 0:   MT(2, 5) = -t2: MT(2, 6) = t3
MT(3, 1) = 0:   MT(3, 2) = t3:  MT(3, 3) = t4:  MT(3, 4) = 0:   MT(3, 5) = -t3: MT(3, 6) = t5
MT(4, 1) = -t1: MT(4, 2) = 0:   MT(4, 3) = 0:   MT(4, 4) = t1:  MT(4, 5) = 0:   MT(4, 6) = 0
MT(5, 1) = 0:   MT(5, 2) = -t2: MT(5, 3) = -t3: MT(5, 4) = 0:   MT(5, 5) = t2:  MT(5, 6) = -t3
MT(6, 1) = 0:   MT(6, 2) = t3:  MT(6, 3) = t5:  MT(6, 4) = 0:   MT(6, 5) = -t3: MT(6, 6) = t4
Matran = MT
End Function
Khi thực hiện hàm trên: kết quả là dạng mảng cấp 6x6 ta phải chon trước vùng dữ liệu gồm 6 hàng và 6 cột.
Có cách thao tác nào mà ta chỉ cần đặt trỏ chuột vào 1 ô nào đó, sau đó từ vị trí này code tự lấy vùng dữ liệu gồm 6 hàng, 6 cột không ạ (Lấy về phía dưới, bên phải vj trí trỏ chuột)?
Em cám ơn !
 
Upvote 0
Bác ptm0412 có thể cho e hỏi đoạn code nào có thể làm được việc sau:
PHP:
Public Function Matran(E As Double, A As Double, J As Double, l As Double)
Dim MT(1 To 6, 1 To 6)
Dim t1, t2, t3, t4, t5 As Double
t1 = E * A / l: t2 = 12 * E * J / (l ^ 3): t3 = 6 * E * J / (l ^ 2): t4 = 4 * E * J / l: t5 = 2 * E * J / l
MT(1, 1) = t1:  MT(1, 2) = 0:   MT(1, 3) = 0:   MT(1, 4) = -t1: MT(1, 5) = 0:   MT(1, 6) = 0
MT(2, 1) = 0:   MT(2, 2) = t2:  MT(2, 3) = t3:  MT(2, 4) = 0:   MT(2, 5) = -t2: MT(2, 6) = t3
MT(3, 1) = 0:   MT(3, 2) = t3:  MT(3, 3) = t4:  MT(3, 4) = 0:   MT(3, 5) = -t3: MT(3, 6) = t5
MT(4, 1) = -t1: MT(4, 2) = 0:   MT(4, 3) = 0:   MT(4, 4) = t1:  MT(4, 5) = 0:   MT(4, 6) = 0
MT(5, 1) = 0:   MT(5, 2) = -t2: MT(5, 3) = -t3: MT(5, 4) = 0:   MT(5, 5) = t2:  MT(5, 6) = -t3
MT(6, 1) = 0:   MT(6, 2) = t3:  MT(6, 3) = t5:  MT(6, 4) = 0:   MT(6, 5) = -t3: MT(6, 6) = t4
Matran = MT
End Function
Khi thực hiện hàm trên: kết quả là dạng mảng cấp 6x6 ta phải chon trước vùng dữ liệu gồm 6 hàng và 6 cột.
Có cách thao tác nào mà ta chỉ cần đặt trỏ chuột vào 1 ô nào đó, sau đó từ vị trí này code tự lấy vùng dữ liệu gồm 6 hàng, 6 cột không ạ (Lấy về phía dưới, bên phải vj trí trỏ chuột)?
Em cám ơn !
Thì viết thêm 1 sub nữa
Ví dụ thế này:
PHP:
Sub Test()
  Dim E As Double, A As Double, J As Double, l As Double
  E = bao nhiêu?
  A = bao nhiêu?
  J = bao nhiêu?
  l = bao nhiêu?
  ActiveCell.Resize(6, 6).Value = Matran(E, A, J, l)
End Sub
Đặt con trỏ chuột vào 1 cell rồi chạy sub này ---> không khó đối với bạn chứ?
 
Upvote 0
Upvote 0
Em cám ơn hai bác. Nhưng quả thực nếu không tạo Sub khác thì không giải quyết được vấn đề này sao?
Thân !
 
Upvote 0
Hoặc viết công thức = Index(Matran(E,A,J,l),Rows($1:1),Columns($A:A))
rồi fill qua phải và xuống dưới.
Cái này mà dùng INDEX thì.. hơi phí sư phụ à
Nếu dùng công thức, ta cứ quét chọn 6 dòng, 6 cột rồi gõ vào thanh Formula công thức =Matran(E,A,J,l), bấm Ctrl + Shift + Enter là được rồi
-----------------------------------
Em cám ơn hai bác. Nhưng quả thực nếu không tạo Sub khác thì không giải quyết được vấn đề này sao?
Thân !
Thế bạn có ý tưởng gì khác chăng? Hoặc giả ý bạn mong muốn nó phải như thế nào?
 
Upvote 0
Cái này mà dùng INDEX thì.. hơi phí sư phụ à
Nếu dùng công thức, ta cứ quét chọn 6 dòng, 6 cột rồi gõ vào thanh Formula công thức =Matran(E,A,J,l), bấm Ctrl + Shift + Enter là được rồi
-----------------------------------
Đúng là em đang thao tác hàm trên như đúng ý bác nói.
Nhưng em mong muốn như thế này:
+ Em không muốn quét đồng thời 6 dòng , 6 cột
+ Khi thực hiện hàm chỉ cần chọn 1 ô bất kỳ để gõ hàm, sau đó thì hàm sẽ tự chọn 6 hàng, 6 cột để tính ra kết quả của hàm này.
+ Có thể bẫy lỗi như sau không ạ: Khi mình quét chọn không đủ 6 hàng , 6 cột sẽ đưa ra thông báo lỗi
Em cám ơn!
 
Upvote 0
Đúng là em đang thao tác hàm trên như đúng ý bác nói.
Nhưng em mong muốn như thế này:
+ Em không muốn quét đồng thời 6 dòng , 6 cột
+ Khi thực hiện hàm chỉ cần chọn 1 ô bất kỳ để gõ hàm, sau đó thì hàm sẽ tự chọn 6 hàng, 6 cột để tính ra kết quả của hàm này.
+ Có thể bẫy lỗi như sau không ạ: Khi mình quét chọn không đủ 6 hàng , 6 cột sẽ đưa ra thông báo lỗi
Em cám ơn!
Dùng sự kiện WorksheetChange xem!
Chẳng hạn thế này:
PHP:
Private Sub Worksheet_Change(ByVal Target As Range)
  On Error GoTo ExitSub
  If Left(Target.Formula, 7) = "=Matran" Then Target.Resize(6, 6).FormulaArray = Target.Formula
ExitSub:
End Sub
Bạn nói rằng:
+ Khi thực hiện hàm chỉ cần chọn 1 ô bất kỳ để gõ hàm, sau đó thì hàm sẽ tự chọn 6 hàng, 6 cột để tính ra kết quả của hàm này.
Vậy sao lại thêm:
+ Có thể bẫy lỗi như sau không ạ: Khi mình quét chọn không đủ 6 hàng , 6 cột sẽ đưa ra thông báo lỗi
Chỉ gõ công thức tại 1 cell, có cần quét gì đâu mà bẫy lỗi
 
Upvote 0
Web KT
Back
Top Bottom