Trang 6/7 đầuđầu ... 2 3 4 5 6 7 cuốicuối
Hiển thị kết quả tìm kiếm từ 51 đến 60 trên tổng số: 68

Ðề tài: Sort trong mảng Arr

  1. Trích Nguyên văn bởi HieuCD View Post
    vận hành của listbox mình không rành lắm nên không biết kiểm tra như thế nào
    Thì kiểm tra như code tôi ghi ở trên đó
    Thật ra thì mảng lấy từ bảng tính hay lấy từ listbox cũng như như thôi
    Ví dụ tôi có:
    Code:
    arr1 = Range("A1:D10").Value
    tôi nạp arr1 vào listbox:
    Code:
    Me.ListBox1.List = arr1
    Giờ tôi lại lấy dữ liệu từ listbox nạp vào 1 mảng
    Code:
    arr2 = Me.ListBox1.List
    Kết quả 2 mảng arr1 và arr2 là như nhau. Vậy điều gì khiến cho code sort chạy đúng khi lấy dữ liệu từ Range nhưng lại sai khi lấy từ ListBox?
    Vấn đề nằm ở chỗ: Tuy 2 mảng arr1 và arr2 giống nhau nhưng có 1 điểm khác biệt "chết người", đó là mảng lấy từ Range sẽ có chuẩn BASE 1 (LBound(arr1) = 1) trong khi mảng lấy từ listbox lại có chuẩn BASE 0 (LBound(arr2) =0)
    ----------------------------
    Điều tôi muốn nhấn mạnh ở đây là:
    - Đã gọi là MẢNG BẤT KỲ thì coi như ta không biết trước được BASE = bao nhiêu (LBound(mảng) = bao nhiêu chưa biết)
    - Khi viết code cho mảng, chúng ta không thể chủ quan mà xem nó như Range
    - Mảng có thể lấy từ Range nhưng trong thực tế sẽ có trường hợp lấy từ nơi khác, chẳng hạn mảng do ta tự tạo ra, mảng lấy từ các control... vân vân...
    - Trong 1 số trường hợp, để chuẩn hóa mảng luôn là BASE 1, người ta cho đoạn Option Base 1 lên đầu code (dưới dòng Option Explicit). Tuy nhiên điều này cũng chỉ có tác dụng với mảng do ta tự tạo ra và hoàn toàn không ăn thua gì đối với mảng được lấy từ nơi khác (có thể thí nghiệm để chứng minh)

    Nói tóm lại nếu ta viết code thế này:
    Code:
    For i = 1 to UBound(arr,1)
     .....
    Next
    Thì sự chủ quan của ta nằm ở chính con số 1 (tô đỏ ở trên). Bởi làm sao ta chắc ăn 100% rằng chỉ số index đầu tiên của arr là 1 (trừ phi bạn xác định ngay từ đầu đối số của hàm phải là Range)
    Chắc ăn ta luôn viết:
    Code:
    For i = LBound(arr,1)  to UBound(arr,1)
     .....
    Next
    - Mục đích viết code sort mảng 2D chủ yếu là muốn nó hoạt động ở đâu đó khác với môi trường bảng tính chứ ngay trên bảng tính Excel ta đã có công cụ sort rồi, cần gì phải viết thêm
    -----------------------------------

    Ôi... dài dòng quá! Không biết có ai hiểu không nữa

  2. Trích Nguyên văn bởi ndu96081631 View Post
    Thì kiểm tra như code tôi ghi ở trên đó
    Thật ra thì mảng lấy từ bảng tính hay lấy từ listbox cũng như như thôi
    Ví dụ tôi có:
    Code:
    arr1 = Range("A1:D10").Value
    tôi nạp arr1 vào listbox:
    Code:
    Me.ListBox1.List = arr1
    Giờ tôi lại lấy dữ liệu từ listbox nạp vào 1 mảng
    Code:
    arr2 = Me.ListBox1.List
    Kết quả 2 mảng arr1 và arr2 là như nhau. Vậy điều gì khiến cho code sort chạy đúng khi lấy dữ liệu từ Range nhưng lại sai khi lấy từ ListBox?
    Vấn đề nằm ở chỗ: Tuy 2 mảng arr1 và arr2 giống nhau nhưng có 1 điểm khác biệt "chết người", đó là mảng lấy từ Range sẽ có chuẩn BASE 1 (LBound(arr1) = 1) trong khi mảng lấy từ listbox lại có chuẩn BASE 0 (LBound(arr2) =0)
    ----------------------------
    Điều tôi muốn nhấn mạnh ở đây là:
    - Đã gọi là MẢNG BẤT KỲ thì coi như ta không biết trước được BASE = bao nhiêu (LBound(mảng) = bao nhiêu chưa biết)
    - Khi viết code cho mảng, chúng ta không thể chủ quan mà xem nó như Range
    - Mảng có thể lấy từ Range nhưng trong thực tế sẽ có trường hợp lấy từ nơi khác, chẳng hạn mảng do ta tự tạo ra, mảng lấy từ các control... vân vân...
    - Trong 1 số trường hợp, để chuẩn hóa mảng luôn là BASE 1, người ta cho đoạn Option Base 1 lên đầu code (dưới dòng Option Explicit). Tuy nhiên điều này cũng chỉ có tác dụng với mảng do ta tự tạo ra và hoàn toàn không ăn thua gì đối với mảng được lấy từ nơi khác (có thể thí nghiệm để chứng minh)

    Nói tóm lại nếu ta viết code thế này:
    Code:
    For i = 1 to UBound(arr,1)
     .....
    Next
    Thì sự chủ quan của ta nằm ở chính con số 1 (tô đỏ ở trên). Bởi làm sao ta chắc ăn 100% rằng chỉ số index đầu tiên của arr là 1 (trừ phi bạn xác định ngay từ đầu đối số của hàm phải là Range)
    Chắc ăn ta luôn viết:
    Code:
    For i = LBound(arr,1)  to UBound(arr,1)
     .....
    Next
    - Mục đích viết code sort mảng 2D chủ yếu là muốn nó hoạt động ở đâu đó khác với môi trường bảng tính chứ ngay trên bảng tính Excel ta đã có công cụ sort rồi, cần gì phải viết thêm
    -----------------------------------

    Ôi... dài dòng quá! Không biết có ai hiểu không nữa
    cám ơn bạn, góp ý của bạn rất hay, mình sẽ nghiên cứu và chỉnh lại các tham số code sau
    ngoài ra khi nhấn command chạy list liên tục thì bị lổi, mình đã bẩy lổi nhưng không biết tại sao không được, bạn xem giúp
    Tập tin đính kèm Tập tin đính kèm

  3. Trích Nguyên văn bởi HieuCD View Post
    cám ơn bạn, góp ý của bạn rất hay, mình sẽ nghiên cứu và chỉnh lại các tham số code sau
    Gợi ý:
    Khi bạn viết nhanh một sub, giải quyết vấn đề tại chỗ, thì bạn có thể tuỳ tiện dùng thông số mà mình đã biết trước for i = 1 to 10, hay for i = 0 to gì gì đó. Làm như vậy cho nhanh gọn. Những con số 0, 1, vv... trong lập trình gọi là magic numbers (số từ trên trời rớt xuống). Tức là những con số mà bạn biết trước sẽ luôn như vây (hằng).
    Nhưng khi bạn giải quyết một vấn đề phức tạp hơn, có nhiều sub/function; và có thể bạn sẽ cóp các sub/function này lại để dùng lâu dài thì nên tránh dùng magic numbers. Nhũng con só này nếu tính được thì nên dùng hàm để tính (điển hình là LBound, UBound cho mảng); không tính được (điển hình là PI) thì bạn cho vào biến Const và đặt lên đầu module hoạc sub (tuỳ theo bạn muốn nó là toàn cục hay cục bộ). Nên nhớ là từ khoá Const được ngôn ngữ đưa ra để khai báo hằng. Ngừoi đọc code nhìn vào thì để ý ngay là code bạn có những thong số như thế.
    (ngừoi đọc code có thể chính là bạn 1 vài năm sau. Néu bạn dùng nhiều magic numbers thì 1 vài năm sau, đọc lại code có thể chính bạn cũng khong hiểu)

  4. Trích Nguyên văn bởi VetMini View Post
    Gợi ý:
    Khi bạn viết nhanh một sub, giải quyết vấn đề tại chỗ, thì bạn có thể tuỳ tiện dùng thông số mà mình đã biết trước for i = 1 to 10, hay for i = 0 to gì gì đó. Làm như vậy cho nhanh gọn. Những con số 0, 1, vv... trong lập trình gọi là magic numbers (số từ trên trời rớt xuống). Tức là những con số mà bạn biết trước sẽ luôn như vây (hằng).
    Nhưng khi bạn giải quyết một vấn đề phức tạp hơn, có nhiều sub/function; và có thể bạn sẽ cóp các sub/function này lại để dùng lâu dài thì nên tránh dùng magic numbers. Nhũng con só này nếu tính được thì nên dùng hàm để tính (điển hình là LBound, UBound cho mảng); không tính được (điển hình là PI) thì bạn cho vào biến Const và đặt lên đầu module hoạc sub (tuỳ theo bạn muốn nó là toàn cục hay cục bộ). Nên nhớ là từ khoá Const được ngôn ngữ đưa ra để khai báo hằng. Ngừoi đọc code nhìn vào thì để ý ngay là code bạn có những thong số như thế.
    (ngừoi đọc code có thể chính là bạn 1 vài năm sau. Néu bạn dùng nhiều magic numbers thì 1 vài năm sau, đọc lại code có thể chính bạn cũng khong hiểu)
    cám ơn bạn, đúng như bạn góp ý, chỉnh lại các tham số quá rắc rối, nó chạy lung tung, đành phải viết lại code mới, và sau nầy muốn thêm các điều kiện sort 4, 5, 6 cũng dể
    code kết hợp ArrayList và Dictionary và duyệt qua tất cả các dòng của các cột sort và thêm 1 for next lấy kết quả, nên có thể chạy chậm hơn code trước
    Tập tin đính kèm Tập tin đính kèm

  5. Trích Nguyên văn bởi HieuCD View Post
    cám ơn bạn, góp ý của bạn rất hay, mình sẽ nghiên cứu và chỉnh lại các tham số code sau
    ngoài ra khi nhấn command chạy list liên tục thì bị lổi, mình đã bẩy lổi nhưng không biết tại sao không được, bạn xem giúp
    Thì bạn cũng thấy qua thí nghiệm rồi đó:
    - Đầu tiên form load thì listbox có 5 cột
    - Bấm CommandButton, listbox còn 4 cột
    - Bấm tiếp CommandButton, listbox còn 3 cột
    Và đương nhiên bấm tiếp nữa sẽ bị lỗi, bởi code button:
    Code:
    Private Sub CommandButton1_Click()
       Dim aSrc
      aSrc = Me.ListBox1.List
      Test1 = UBound(aSrc, 1)
      Test2 = UBound(aSrc, 2)
      Dim aDes
      aDes = SortArray(aSrc, False, 3)
      Me.ListBox1.List = aDes
    End Sub
    Sort cột 3 nhưng hiện tại có cột 3 đâu mà sort?
    -----------------------------------------------------------
    Vậy vấn đề nằm ở chỗ BASE 0 và BASE 1 như tôi đã đề câp ở bài 51. Cụ thể trong code của bạn:
    Code:
    Function SortArray1Col(ByVal SourceArray, ByVal ColIndex As Byte, Optional ByVal Order As Boolean = True, _
                    Optional ByVal HasTitle As Boolean = False, Optional ByVal HideTitle As Boolean = False)
    
      R = UBound(Darr) + HasTitle 'so dong du lieu Sort
      LenR = Len(CStr(R))         'so chu so cua thu tu dong
      
      For i = 1 To R
    
    End Function
    Phải xem lại chỗ màu đỏ
    ----------------------
    Để đơn giản hóa vấn đề, khuyên bạn nên làm bài toán dễ hơn, chẳng hạn lọc duy nhất từ mảng 2 chiều theo cột chỉ định, ví dụ:
    Code:
    Function Unique2DArray(ByVal Source2D, ByVal ColIndex As Long)
       ........
    End Function
    Trong đó Source2D là mảng bất kỳ.
    Nếu bạn làm được bài toán này lấy source trên range hay trên listbox đều ổn, tự nhiên bạn sẽ có ngay kinh nghiêm để làm tiếp bài toán sort2d
    thay đổi nội dung bởi: ndu96081631, 20-03-17 lúc 11:41 AM

  6. Trích Nguyên văn bởi ndu96081631 View Post
    Thì bạn cũng thấy qua thí nghiệm rồi đó:
    - Đầu tiên form load thì listbox có 5 cột
    - Bấm CommandButton, listbox còn 4 cột
    - Bấm tiếp CommandButton, listbox còn 3 cột
    Và đương nhiên bấm tiếp nữa sẽ bị lỗi, bởi code button:
    Code:
    Private Sub CommandButton1_Click()
       Dim aSrc
      aSrc = Me.ListBox1.List
      Test1 = UBound(aSrc, 1)
      Test2 = UBound(aSrc, 2)
      Dim aDes
      aDes = SortArray(aSrc, False, 3)
      Me.ListBox1.List = aDes
    End Sub
    Sort cột 3 nhưng hiện tại có cột 3 đâu mà sort?
    -----------------------------------------------------------
    Vậy vấn đề nằm ở chỗ BASE 0 và BASE 1 như tôi đã đề câp ở bài 51. Cụ thể trong code của bạn:
    Code:
    Function SortArray1Col(ByVal SourceArray, ByVal ColIndex As Byte, Optional ByVal Order As Boolean = True, _
                    Optional ByVal HasTitle As Boolean = False, Optional ByVal HideTitle As Boolean = False)
    
      R = UBound(Darr) + HasTitle 'so dong du lieu Sort
      LenR = Len(CStr(R))         'so chu so cua thu tu dong
      
      For i = 1 To R
    
    End Function
    Phải xem lại chỗ màu đỏ
    ----------------------
    Để đơn giản hóa vấn đề, khuyên bạn nên làm bài toán dễ hơn, chẳng hạn lọc duy nhất từ mảng 2 chiều theo cột chỉ định, ví dụ:
    Code:
    Function Unique2DArray(ByVal Source2D, ByVal ColIndex As Long)
       ........
    End Function
    Trong đó Source2D là mảng bất kỳ.
    Nếu bạn làm được bài toán này lấy source trên range hay trên listbox đều ổn, tự nhiên bạn sẽ có ngay kinh nghiêm để làm tiếp bài toán sort2d
    cám ơn bạn, mình đang chỉnh lại code
    bạn góp ý thêm code ở bài #54

  7. Trích Nguyên văn bởi ndu96081631 View Post
    Bạn nên làm vài cuộc thí nghiệm để kiểm chứng. Ví dụ: Lấy dữ liệu từ bảng tính lên ListBox rồi sort gì gì đó. Xong lấy dữ liệu từ chính cái ListBox ấy để sort, sau đó nạp kết quả trở lại ListBox
    Đầu tiên thử nghiệm sort 1 cột thôi nhé
    Code:
    Private Sub UserForm_Initialize()
      Dim aSrc
      aSrc = Range("A2:E28").Value
      Dim aDes
      aDes = SortArray(aSrc, False, 3)
      Me.ListBox1.List = aDes
    End Sub 
    Private Sub CommandButton1_Click()
       Dim aSrc
      aSrc = Me.ListBox1.List
      Dim aDes
      aDes = SortArray(aSrc, False, 3)
      Me.ListBox1.List = aDes
    End Sub
    (vẽ thêm 1 CommandButton)
    Để ý 2 dòng code màu đỏ là y chang nhau. Nếu kết quả nhận được khác nhau thì chứng tỏ code có vấn đề
    đã chỉnh lại code chạy theo mảng hoặc range, bạn góp ý dùm
    Tập tin đính kèm Tập tin đính kèm

  8. Trích Nguyên văn bởi HieuCD View Post
    đã chỉnh lại code chạy theo mảng hoặc range, bạn góp ý dùm
    Vẫn chưa được bạn à:
    - Đầu tiên show form, listbox có 5 cột
    - Bấm Button, listbox còn 4 cột
    - Càng bấm, số cột càng mất dần
    Nói chung dữ liệu lấy từ range hay từ listbox thì chúng cũng có 5 cột, cớ sao qua quá trình xử lý lại bị mất đi? Có nghĩa là bạn vẫn chưa giải quyết được hoàn toàn vấn đề base 0 và base 1 của mảng
    (kết quả chính xác trước rồi mới bàn tiếp về giải thuật)

  9. Tôi gửi bạn file dưới đây để tham khảo. Hàm sort 1 cột đơn giản thôi nhưng chắc ăn kết quả được bảo toàn
    Code:
    Function Sort2DArray(ByVal Source2D, ByVal ColIndex As Long, Optional ByVal Order As Boolean = False)
      Dim aSrc, tmp
      Dim oArrList As Object
      Dim lR As Long, lC As Long, idx As Long, lPos As Long
      Dim lFstRow As Long, lEndRow As Long, lFstCol As Long, lEndCol As Long
      aSrc = Source2D
      lFstRow = LBound(aSrc, 1): lEndRow = UBound(aSrc, 1)
      lFstCol = LBound(aSrc, 2): lEndCol = UBound(aSrc, 2)
      Set oArrList = CreateObject("System.Collections.ArrayList")
      For lR = lFstRow To lEndRow
        tmp = aSrc(lR, ColIndex)
        oArrList.Add tmp
      Next
      oArrList.Sort
      If Order Then oArrList.Reverse
      ReDim aPos(oArrList.Count - 1)  'mảng chuẩn base 0
      ReDim aDes(lFstRow To lEndRow, lFstCol To lEndCol)
      For lR = lFstRow To lEndRow
        tmp = aSrc(lR, ColIndex)
        idx = oArrList.IndexOf(tmp, 0)
        lPos = idx + lFstRow + aPos(idx) ''vi tri tùy biến theo chuẩn base của mảng nguồn
        For lC = lFstCol To lEndCol
          aDes(lPos, lC) = aSrc(lR, lC)
        Next
        aPos(idx) = aPos(idx) + 1
      Next
      Sort2DArray = aDes
    End Function
    Không bàn về giải thuật, bạn cứ xem cách tôi xử lý base 0, base 1 thì sẽ rõ: hoàn toàn không có bất kỳ con số (0 hay 1) gì được gán vào chỉ số index đầu tiên của mảng cả (trừ phi tôi đã định trước mảng đó thuộc chuẩn nào)
    Tập tin đính kèm Tập tin đính kèm

  10. Trích Nguyên văn bởi ndu96081631 View Post
    Tôi gửi bạn file dưới đây để tham khảo. Hàm sort 1 cột đơn giản thôi nhưng chắc ăn kết quả được bảo toàn
    Code:
    Function Sort2DArray(ByVal Source2D, ByVal ColIndex As Long, Optional ByVal Order As Boolean = False)
      Dim aSrc, tmp
      Dim oArrList As Object
      Dim lR As Long, lC As Long, idx As Long, lPos As Long
      Dim lFstRow As Long, lEndRow As Long, lFstCol As Long, lEndCol As Long
      aSrc = Source2D
      lFstRow = LBound(aSrc, 1): lEndRow = UBound(aSrc, 1)
      lFstCol = LBound(aSrc, 2): lEndCol = UBound(aSrc, 2)
      Set oArrList = CreateObject("System.Collections.ArrayList")
      For lR = lFstRow To lEndRow
        tmp = aSrc(lR, ColIndex)
        oArrList.Add tmp
      Next
      oArrList.Sort
      If Order Then oArrList.Reverse
      ReDim aPos(oArrList.Count - 1)  'mảng chuẩn base 0
      ReDim aDes(lFstRow To lEndRow, lFstCol To lEndCol)
      For lR = lFstRow To lEndRow
        tmp = aSrc(lR, ColIndex)
        idx = oArrList.IndexOf(tmp, 0)
        lPos = idx + lFstRow + aPos(idx) ''vi tri tùy biến theo chuẩn base của mảng nguồn
        For lC = lFstCol To lEndCol
          aDes(lPos, lC) = aSrc(lR, lC)
        Next
        aPos(idx) = aPos(idx) + 1
      Next
      Sort2DArray = aDes
    End Function
    Không bàn về giải thuật, bạn cứ xem cách tôi xử lý base 0, base 1 thì sẽ rõ: hoàn toàn không có bất kỳ con số (0 hay 1) gì được gán vào chỉ số index đầu tiên của mảng cả (trừ phi tôi đã định trước mảng đó thuộc chuẩn nào)
    code của bạn quá chuẩn, mình sẽ viết lại theo cách nầy
    code viết theo kiểu đụng đâu chỉnh đó, hơi rối, đưa lên cho vui, sẽ chỉnh lại theo cách của bạn
    Tập tin đính kèm Tập tin đính kèm

Trang 6/7 đầuđầu ... 2 3 4 5 6 7 cuốicuối

Thông tin về chủ đề này

Users Browsing this Thread

Hiện có 1 người đang xem đề tài này. (0 thành viên và 1 khách)

Bookmarks

Bookmarks

Quyền Sử Dụng Ở Diễn Ðàn

  • Bạn không thể đăng đề tài mới
  • Bạn không thể đăng trả lời
  • Bạn không thể đăng file đính kèm.
  • Bạn không thể sửa bài viết.
  •