VBA cộng mảng liên tục và gián đoạn

Liên hệ QC
Hu hu... hu.... bác ơi, bác chú thích rõ như thế, nhưng cháu không hiểu thuật toán như nào? Thế mà bác viết được như vậy? Bác có thể chỉ dẫn cho cháu nguyên lý như nào được không hả bác?
Đây là code dạng khó có tới 4 vòng For lồng nhau, những người mới bắt đầu làm quen với code khó có thể phân tích và viết được code
Mình quan sát dữ liệu và kết quả truy xuất, tìm mối liên hệ có tính qui luật, thử các con số và các phương án ... từ đó mới đưa ra thuật toán, chạy thử không được thì chỉnh lại từ từ, sai nhiều lần mới được 1 kết quả đúng
Bạn nên bắt đầu với code 1 vài vòng For cho quen rồi mới tới nhiều vòng For, phải có thời gian mới ngộ được
Sở trường của mình là thêm bớt, cộng trừ nhân chia các con số để ra con số phù hợp:)
 
Mã:
Sub GPE4() 'tong quat
  Dim sArr() 'Mang du lieu
  Dim Res() 'Mang ket qua
  Dim i As Long, j As Long, sR As Long, mk As Byte, nk As Byte
  Const n = 2 'so dòng cong
  Const m = 3 'so mang ket qua
  Const d = 2 'Só dòng trong giua 2 ket qua
  Const sRngStr = "C2:AA13" 'Dia chi vùng du lieu
  Const rRngStr = "C17" 'Dia chi ket qua
 
  sArr = Range(sRngStr).Value 'Gán du lieu vào mang du lieu
  sR = UBound(sArr) - (n - 1 + m - 1) 'so dong mang ket qua
  For mk = 1 To m 'Chay mang ket qua mk
    ReDim Res(1 To sR, 1 To UBound(sArr, 2)) 'Khai báo mang ket qua voi so dòng: sR và so cot: UBound(sArr, 2)
    For i = 1 To sR 'Chay tu dong dau toi dòng cuoi mang ket qua
      For j = 1 To UBound(sArr, 2) 'Chay tu cot dau toi cot cuoi
        If TypeName(sArr(i, j)) = "Double" Then 'Neu có du lieu
          For nk = 0 To n - 1
            Res(i, j) = Res(i, j) + sArr(i + mk + nk - 1, j) 'tính ket qua
          Next nk
        End If
      Next j
    Next i
  Range(rRngStr).Offset((mk - 1) * (sR + d)).Resize(sR, UBound(Res, 2)) = Res 'gán ket qua vào dia chi ket qua
  Next mk
End Sub
Bác ơi, cháu đã sửa lại code như này mà tại sao áp dụng cho bài này lại không được bác nhỉ. cháu đã cho thêm vào vòng lặp "Z" nữa rồi. Bác chỉ giùm cháu với.
Sub GPE5() 'tong quat
Dim sArr() 'Mang du lieu
Dim Res() 'Mang ket qua
Dim i As Long, j As Long, sR As Long, mk As Byte, nk As Byte, z As Byte
Const n = 2 + z 'so dòng cong
Const m = 3 'so mang ket qua
Const d = 2 'Só dòng trong giua 2 ket qua
Const sRngStr = "C2:AA13" 'Dia chi vùng du lieu
Const rRngStr = "C17" 'Dia chi ket qua

sArr = Range(sRngStr).Value 'Gán du lieu vào mang du lieu
sR = UBound(sArr) - (n - 1 + m - 1) 'so dong mang ket qua
For mk = 1 To m 'Chay mang ket qua mk
ReDim Res(1 To sR, 1 To UBound(sArr, 2)) 'Khai báo mang ket qua voi so dòng: sR và so cot: UBound(sArr, 2)
For i = 1 To sR 'Chay tu dong dau toi dòng cuoi mang ket qua
For j = 1 To UBound(sArr, 2) 'Chay tu cot dau toi cot cuoi
If TypeName(sArr(i, j)) = "Double" Then 'Neu có du lieu
For z = 1 To 2
For nk = 0 To n - 1
Res(i, j) = Res(i, j) + sArr(i + mk + nk - 1, j) 'tính ket qua
Next z
Next nk
End If
Next j
Next i
Range(rRngStr).Offset((mk - 1) * (sR + d)).Resize(sR, UBound(Res, 2)) = Res 'gán ket qua vào dia chi ket qua
Next mk
End Sub
Cháu cảm ơn bác!
 

File đính kèm

Bác ơi, cháu đã sửa lại code như này mà tại sao áp dụng cho bài này lại không được bác nhỉ. cháu đã cho thêm vào vòng lặp "Z" nữa rồi. Bác chỉ giùm cháu với.
Sub GPE5() 'tong quat
Dim sArr() 'Mang du lieu
Dim Res() 'Mang ket qua
Dim i As Long, j As Long, sR As Long, mk As Byte, nk As Byte, z As Byte
Const n = 2 + z 'so dòng cong
Const m = 3 'so mang ket qua
Const d = 2 'Só dòng trong giua 2 ket qua
Const sRngStr = "C2:AA13" 'Dia chi vùng du lieu
Const rRngStr = "C17" 'Dia chi ket qua

sArr = Range(sRngStr).Value 'Gán du lieu vào mang du lieu
sR = UBound(sArr) - (n - 1 + m - 1) 'so dong mang ket qua
For mk = 1 To m 'Chay mang ket qua mk
ReDim Res(1 To sR, 1 To UBound(sArr, 2)) 'Khai báo mang ket qua voi so dòng: sR và so cot: UBound(sArr, 2)
For i = 1 To sR 'Chay tu dong dau toi dòng cuoi mang ket qua
For j = 1 To UBound(sArr, 2) 'Chay tu cot dau toi cot cuoi
If TypeName(sArr(i, j)) = "Double" Then 'Neu có du lieu
For z = 1 To 2
For nk = 0 To n - 1
Res(i, j) = Res(i, j) + sArr(i + mk + nk - 1, j) 'tính ket qua
Next z
Next nk
End If
Next j
Next i
Range(rRngStr).Offset((mk - 1) * (sR + d)).Resize(sR, UBound(Res, 2)) = Res 'gán ket qua vào dia chi ket qua
Next mk
End Sub
Cháu cảm ơn bác!
Có nhiều chổ chưa chuẩn code báo lổi:
1/ Const n = 2 + z: gán trực tiếp giá trị không được dùng biến

2/ For z = 1 To 2
For nk = 0 To n - 1
Res(i, j) = Res(i, j) + sArr(i + mk + nk - 1, j) 'tính ket qua
Next z
Next nk
Biến của For và next không tương ứng

Phân tích giải thuật: số dòng cộng lệ thuộc vào biến mảng kết quả, nên không cần For Z, chỉ cần For nk = 0 To n - 1 + ???.
??? là biểu thức theo mk
 
Có nhiều chổ chưa chuẩn code báo lổi:
1/ Const n = 2 + z: gán trực tiếp giá trị không được dùng biến

2/ For z = 1 To 2
For nk = 0 To n - 1
Res(i, j) = Res(i, j) + sArr(i + mk + nk - 1, j) 'tính ket qua
Next z
Next nk
Biến của For và next không tương ứng

Phân tích giải thuật: số dòng cộng lệ thuộc vào biến mảng kết quả, nên không cần For Z, chỉ cần For nk = 0 To n - 1 + ???.
??? là biểu thức theo mk
Hu hu... khó quá bác ui..
 
Tập viết code các tình huống đơn giản trước, khi đã quen tìm mối liên hệ giửa các biến thể hiện qua các biểu thức tính lúc đó mới nâng cấp độ khó lên
Bác ơi cháu thử mãi theo gợ ý của bác mà không được bác à. Bác thêm biểu thức giúp cháu với.
Cháu cảm ơn bác!
 
Bác ơi cháu thử mãi theo gợ ý của bác mà không được bác à. Bác thêm biểu thức giúp cháu với.
Cháu cảm ơn bác!
Mã:
Sub GPE5() 'tong quat
  Dim sArr() 'Mang du lieu
  Dim Res() 'Mang ket qua
  Dim i As Long, j As Long, sR As Long, mk As Byte, nk As Byte
  Const n = 2  'so dòng cong
  Const m = 3 'so mang ket qua
  Const d = 2 'Só dòng trong giua 2 ket qua
  Const sRngStr = "C2:AA13" 'Dia chi vùng du lieu
  Const rRngStr = "C17" 'Dia chi ket qua
 
  sArr = Range(sRngStr).Value 'Gán du lieu vào mang du lieu
  sR = UBound(sArr) - (n - 1 + m - 1) 'so dong mang ket qua
  For mk = 1 To m 'Chay mang ket qua mk
    ReDim Res(1 To sR, 1 To UBound(sArr, 2)) 'Khai báo mang ket qua voi so dòng: sR và so cot: UBound(sArr, 2)
    For i = 1 To sR 'Chay tu dong dau toi dòng cuoi mang ket qua
      For j = 1 To UBound(sArr, 2) 'Chay tu cot dau toi cot cuoi
        If TypeName(sArr(i, j)) = "Double" Then 'Neu có du lieu
          For nk = 0 To n - 1 + mk - 1
            Res(i, j) = Res(i, j) + sArr(i + nk - 1 + m + n - mk - 1, j) 'tính ket qua
          Next nk
        End If
      Next j
    Next i
    Range(rRngStr).Offset((mk - 1) * (sR + d)).Resize(sR, UBound(Res, 2)) = Res 'gán ket qua vào dia chi ket qua
  Next mk
End Sub
 
Mã:
Sub GPE5() 'tong quat
  Dim sArr() 'Mang du lieu
  Dim Res() 'Mang ket qua
  Dim i As Long, j As Long, sR As Long, mk As Byte, nk As Byte
  Const n = 2  'so dòng cong
  Const m = 3 'so mang ket qua
  Const d = 2 'Só dòng trong giua 2 ket qua
  Const sRngStr = "C2:AA13" 'Dia chi vùng du lieu
  Const rRngStr = "C17" 'Dia chi ket qua

  sArr = Range(sRngStr).Value 'Gán du lieu vào mang du lieu
  sR = UBound(sArr) - (n - 1 + m - 1) 'so dong mang ket qua
  For mk = 1 To m 'Chay mang ket qua mk
    ReDim Res(1 To sR, 1 To UBound(sArr, 2)) 'Khai báo mang ket qua voi so dòng: sR và so cot: UBound(sArr, 2)
    For i = 1 To sR 'Chay tu dong dau toi dòng cuoi mang ket qua
      For j = 1 To UBound(sArr, 2) 'Chay tu cot dau toi cot cuoi
        If TypeName(sArr(i, j)) = "Double" Then 'Neu có du lieu
          For nk = 0 To n - 1 + mk - 1
            Res(i, j) = Res(i, j) + sArr(i + nk - 1 + m + n - mk - 1, j) 'tính ket qua
          Next nk
        End If
      Next j
    Next i
    Range(rRngStr).Offset((mk - 1) * (sR + d)).Resize(sR, UBound(Res, 2)) = Res 'gán ket qua vào dia chi ket qua
  Next mk
End Sub
Cháu cảm ơn bác rất nhiều! Bác chỉnh sửa 2 chỗ... Thế mà cháu cứ loay hoay không biết cộng trừ ra sao nữa.
 
Vì các mảng có tính chất kế thừa nên bài này chỉ cần 3 vòng lặp.

Kiểu mì ăn liền
PHP:
Sub Test_MiAnLien()
Const SoPhanTu As Long = 4
Dim MangGoc As Variant, MangKetQua As Variant, ViTriDatKetQua As Range, SoDong As Long, SoCot As Long, i As Long, j As Long, k As Long
MangGoc = Sheet1.Range("C2:AA13").Value
Set ViTriDatKetQua = Sheet1.Range("C17")
SoDong = UBound(MangGoc, 1) - SoPhanTu + 1
SoCot = UBound(MangGoc, 2)
If SoDong < 1 Then Exit Sub
ReDim MangKetQua(1 To SoDong, 1 To SoCot)
For k = 1 To SoPhanTu
    For i = 1 To SoDong
        For j = 1 To SoCot
            MangKetQua(i, j) = MangKetQua(i, j) + MangGoc(i + SoPhanTu - k, j)
        Next
    Next
    If k > 1 Then
        ViTriDatKetQua.Resize(SoDong, SoCot).Value = MangKetQua
        Set ViTriDatKetQua = ViTriDatKetQua.Offset(SoDong + 2)
    End If
Next
End Sub
Kiểu tổng quát
PHP:
Sub Test_TongQuat()
TaoMangCongDon Sheet1.Range("C2:AA13").Value, 4, Sheet1.Range("C17")
End Sub
Sub TaoMangCongDon(ByVal MangGoc As Variant, ByVal SoPhanTu As Long, ByVal ViTriDatKetQua As Range)
Dim MangKetQua As Variant, PhanTuKetQua As Variant, SoDong As Long, i As Long
ReDim MangKetQua(1 To SoPhanTu)
SoDong = UBound(MangGoc, 1) - LBound(MangGoc, 1) + 1 - SoPhanTu + 1
SoCot = UBound(MangGoc, 2) - LBound(MangGoc, 2) + 1
If SoDong > 0 Then
    ReDim PhanTuKetQua(LBound(MangGoc, 1) + SoPhanTu - 1 To UBound(MangGoc, 1), LBound(MangGoc, 2) To UBound(MangGoc, 2))
    For i = 1 To SoPhanTu
        CongMang PhanTuKetQua, MangGoc, -(i - 1)
        MangKetQua(i) = PhanTuKetQua
    Next
    ViTriDatKetQua.Resize((SoPhanTu - 1) * (SoDong + 2), SoCot).ClearContents
    For i = 2 To SoPhanTu
        ViTriDatKetQua.Resize(SoDong, SoCot).Value = MangKetQua(i)
        Set ViTriDatKetQua = ViTriDatKetQua.Offset(SoDong + 2)
    Next
Else
    MsgBox "So phan tu vuot qua kich thuoc mang goc"
End If
End Sub
Private Sub CongMang(ByRef MangGoc As Variant, ByRef MangCong As Variant, ByVal ViTriTuongDoi As Long)
Dim i As Long, j As Long
For i = LBound(MangGoc, 1) To UBound(MangGoc, 1)
    For j = LBound(MangGoc, 2) To UBound(MangGoc, 2)
        MangGoc(i, j) = MangGoc(i, j) + MangCong(i + ViTriTuongDoi, j)
    Next
Next
End Sub
 

File đính kèm

3 giờ mà còn đang mần mò làm. Kiểu này khoảng tháng nữa là thành cao thủ rồi -\\/.
hi hi... em nằm ngủ cũng mơ thấy code chị à, nhưng em thấy khó quá. Khó hơn tất cả các môn em đã và đang học chị à.
Bài đã được tự động gộp:

Vì các mảng có tính chất kế thừa nên bài này chỉ cần 3 vòng lặp.

Kiểu mì ăn liền
PHP:
Sub Test_MiAnLien()
Const SoPhanTu As Long = 4
Dim MangGoc As Variant, MangKetQua As Variant, ViTriDatKetQua As Range, SoDong As Long, SoCot As Long, i As Long, j As Long, k As Long
MangGoc = Sheet1.Range("C2:AA13").Value
Set ViTriDatKetQua = Sheet1.Range("C17")
SoDong = UBound(MangGoc, 1) - SoPhanTu + 1
SoCot = UBound(MangGoc, 2)
If SoDong < 1 Then Exit Sub
ReDim MangKetQua(1 To SoDong, 1 To SoCot)
For k = 1 To SoPhanTu
    For i = 1 To SoDong
        For j = 1 To SoCot
            MangKetQua(i, j) = MangKetQua(i, j) + MangGoc(i + SoPhanTu - k, j)
        Next
    Next
    If k > 1 Then
        ViTriDatKetQua.Resize(SoDong, SoCot).Value = MangKetQua
        Set ViTriDatKetQua = ViTriDatKetQua.Offset(SoDong + 2)
    End If
Next
End Sub
Kiểu tổng quát
PHP:
Sub Test_TongQuat()
TaoMangCongDon Sheet1.Range("C2:AA13").Value, 4, Sheet1.Range("C17")
End Sub
Sub TaoMangCongDon(ByVal MangGoc As Variant, ByVal SoPhanTu As Long, ByVal ViTriDatKetQua As Range)
Dim MangKetQua As Variant, PhanTuKetQua As Variant, SoDong As Long, i As Long
ReDim MangKetQua(1 To SoPhanTu)
SoDong = UBound(MangGoc, 1) - LBound(MangGoc, 1) + 1 - SoPhanTu + 1
SoCot = UBound(MangGoc, 2) - LBound(MangGoc, 2) + 1
If SoDong > 0 Then
    ReDim PhanTuKetQua(LBound(MangGoc, 1) + SoPhanTu - 1 To UBound(MangGoc, 1), LBound(MangGoc, 2) To UBound(MangGoc, 2))
    For i = 1 To SoPhanTu
        CongMang PhanTuKetQua, MangGoc, -(i - 1)
        MangKetQua(i) = PhanTuKetQua
    Next
    ViTriDatKetQua.Resize((SoPhanTu - 1) * (SoDong + 2), SoCot).ClearContents
    For i = 2 To SoPhanTu
        ViTriDatKetQua.Resize(SoDong, SoCot).Value = MangKetQua(i)
        Set ViTriDatKetQua = ViTriDatKetQua.Offset(SoDong + 2)
    Next
Else
    MsgBox "So phan tu vuot qua kich thuoc mang goc"
End If
End Sub
Private Sub CongMang(ByRef MangGoc As Variant, ByRef MangCong As Variant, ByVal ViTriTuongDoi As Long)
Dim i As Long, j As Long
For i = LBound(MangGoc, 1) To UBound(MangGoc, 1)
    For j = LBound(MangGoc, 2) To UBound(MangGoc, 2)
        MangGoc(i, j) = MangGoc(i, j) + MangCong(i + ViTriTuongDoi, j)
    Next
Next
End Sub
Cháu cảm ơn bác @huuthang_bd rất nhiều, cháu lại học thêm được một thuật toán nữa roài.
Cháu chúc bác vạn sự thành công như ý!
 
Giải quyết vấn đề thì như vầy được rồi, nhưng gọi là học bài thì chẳng tới chốn đâu.
Muốn học sử dụng mảng nhiều chiều thì đầu tiên hết phải tìm hiểu cái ngôn ngữ đó nó xếp mảng theo cột hay theo dòng. Nếu mảng lớn thì sử lý đúng chiều nó nhanh hơn.
 
Giải quyết vấn đề thì như vầy được rồi, nhưng gọi là học bài thì chẳng tới chốn đâu.
Muốn học sử dụng mảng nhiều chiều thì đầu tiên hết phải tìm hiểu cái ngôn ngữ đó nó xếp mảng theo cột hay theo dòng. Nếu mảng lớn thì sử lý đúng chiều nó nhanh hơn.
Cảm ơn bác @VetMini đã chỉ dẫn, bác ơi bác giải thích và làm ví dụ cụ thể cho cháu với,.
Cháu cảm ơn bác!
 
Cảm ơn bác @VetMini đã chỉ dẫn, bác ơi bác giải thích và làm ví dụ cụ thể cho cháu với,.
Cháu cảm ơn bác!

Cái tôi nói nó là lý thuyết, làm sao mà cụ thể được.
Gợi ý: chịu khó đọc bài trong mục "những câu hỏi về mảng"
Nếu bạn không biết lựa bài của ai để đọc thì chịu khó tho dõi một thời gian nữa. Hiện nay (*), ở diễn đàn này chỉ có 2 người (nhắc lại, con số 2, không hơn không kém) nói chuyện về lý thuyết.

Chú: tôi nói theo "hiện nay". Trước đây cũng có ngừoi nói chuyện lý thuyết nhưng những người này đã bỏ đi rồi.
 
Web KT

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

Back
Top Bottom