Hiển tất cả các kết quả của tổ hợp

Liên hệ QC
@HieuCD:

Theo lý thuyết thì lời giải chỉ cần mảng 1 chiều. Có lẽ vì lý do cần chuyển kết quả lên worksheet mà bạn phải dùng mảng 2 chiều. Điều này tuy hiệu quả nhưng rất gượng ép và làm giảm tính chất độc lập của cái hàm chính - tức là cái hàm tính tổ hợp của bạn. Nói cách khác, người đọc code hàm HoanVi sẽ thắc mắc không hiểu tại sao trong hàm lại dùng mảng 2 chiều; mãi đến lúc đọc code hàm GPE mới hiểu.

Nếu là tôi thì tôi cho hàm chính chạy trên mảng 1 chiều. Khi cần hiển thị lên worksheet thì chuyển qua mảng 2 chiều.
Dùng code sửa từ code nguyên thủy của bạn thì thời gian chuyển qua mảng 2 chiều chỉ bằng 1/4 thời gian đưa lên bảng tính. Tổng cộng lại, kết quả chỉ chậm hơn code nguyên thủy khoảng 10%.

Mã:
Sub GPE()
  Dim Arr(), Str As String
  t = Timer
  Str = "123456789"
  HoanVi Str, Arr
  [c1] = Timer - t ' cái này mới là thời gian tính thực thụ
  Dim Arr2, i As Long, sd As Long
  sd = UBound(Arr)
  ReDim Arr2(1 To sd, 1 To 1)
  For i = 1 To sd
  Arr2(i, 1) = Arr(i)
  Next i
  [a1].Resize(sd) = Arr2
  [b1] = Timer - t
End Sub

Private Sub HoanVi(ByVal Str As String, Arr())
  Dim n As Long, q As Long, m As Long
  Dim i As Byte, j As Byte, k As Byte, S As Byte
  S = Len(Str)
  ReDim Arr(1 To WorksheetFunction.Fact(S))
  Arr(1) = Str:  n = 1
  For k = 2 To S
    q = n:    n = n * k
    For i = 1 To k - 1
      For m = 1 To n \ k
        q = q + 1
        Arr(q) = Str
        Mid(Arr(q), i, 1) = Mid(Str, k, 1)
        Mid(Arr(q), i + 1, k - i) = Mid(Arr(m), i, k - i)
        If i > 1 Then Mid(Arr(q), 1, i - 1) = Mid(Arr(m), 1, i - 1)
      Next m
    Next i
  Next k
End Sub
Cám ơn bạn:)
Mình chỉnh lại biến hợp lý hơn
Mã:
Private Sub HoanVi(ByVal Str As String, Arr())
  Dim n As Long, q As Long, m As Long
  Dim i As Byte, j As Byte, k As Byte, S As Byte
  S = Len(Str)
  ReDim Arr(1 To WorksheetFunction.Fact(S))
  q = 1:   n = 1
  Arr(q) = Str
  For k = 2 To S
    n = n * (k - 1) 'So kha nang cua Hoan Vi bac k-1
    For i = 1 To k - 1
      For m = 1 To n
        q = q + 1
        Arr(q) = Str
        Mid(Arr(q), i, 1) = Mid(Str, k, 1)
        Mid(Arr(q), i + 1, k - i) = Mid(Arr(m), i, k - i)
        If i > 1 Then Mid(Arr(q), 1, i - 1) = Mid(Arr(m), 1, i - 1)
      Next m
    Next i
  Next k
End Sub
 
Tự thuở xa xưa, các bậc trưởng thượng trên diễn đàn này đã quen với cách dùng "On Error..." để bẫy lỗi.
may quá, tôi không phải bậc trưởng thượng và cũng không dùng On error Resume next, và hễ có dịp là tôi dặn các em cháu của tôi là nên giới hạn dùng.
If (Not a1) = -1 Then ' nếu a1 chưa có địa chỉ thì con trỏ là null, và not của nó là -1
Cám ơn anh vì tôi học thêm được 1 điều. Tuy nhiên tôi có 1 thắc mắc khi thực hành ngay điều này: Tôi viết 1 thủ tục như sau, và kết quả (Not Arr4) lại không đúng như tôi đoán, nhờ anh giải thích giúp:

Mã:
Sub test()
Dim Arr1(10), Arr2(), Arr3(), Arr4
MsgBox (Not Arr1) ' <> -1
ReDim Arr2(1 To 10)
MsgBox (Not Arr2) ' <> -1
Arr3 = Array(1, 2)
MsgBox (Not Arr3) '<> -1
MsgBox (Not Arr4) ' -1
Arr4 = Split("s,e", ",")
MsgBox Arr4(0) & "+" & Arr4(1) ' s+e
MsgBox (Not Arr4) ' Type mismatch (tôi đoán là <> -1 giống Arr3)

End Sub
- Ban đầu Not Arr2, Not Arr3, Not Arr4 đều bằng -1
- Arr1 khai báo sẵn kích thước nên Not Arr1 <> -1
- Arr2 sau khi Redim thì Not Arr2 <> -1
- Gắn 1 mảng giá trị cụ thể vào Arr3 thì Not Arr3 <> -1
- Gắn giá trị cho Arr4 bằng hàm Split (kiểm tra lại thấy có giá trị), nhưng Not Arr4 bị lỗi Type Mismatch
 
Lần chỉnh sửa cuối:
VB/VBA dùng safe pointer để trả về địa chỉ khi bạn đề cập đến mảng động (truy cứu bằng tên). Toán tử Not trong trường hợp này
Arr4 căn bản là một Variant. Khi chưa được gán trị thì VBA cũng dùng safe pointer, nhưng khi đã được gán trị thì VBA sẽ cố tìm hàm/trị mặc định để trả về. Trong trường hợp này, nó không có hàm/trị mặc định.
 
Web KT
Back
Top Bottom