Sort mảng 2 chiều

Liên hệ QC

anhtuan1066

Thành viên gạo cội
Tham gia
10/3/07
Bài viết
5,802
Được thích
6,911
Đầu tiên xin mời các bạn xem qua topic này:
http://www.giaiphapexcel.com/forum/showthread.php?38005-Sắp-xếp-mảng-dữ-liệu-không-sử-dụng-vòng-lặp&
Ở đây người ta dùng JScript để sort mảng 1 chiều
Mượn tạm sự trợ giúp này, tôi xây dụng code sort mảng 2 chiều như sau:
PHP:
Function Sort1DArray(Arr, Optional isText As Boolean = False, Optional isDESC As Boolean = False)
  Dim sCommand As String
  sCommand = "('" & Join(Arr, vbBack) & "').split('" & vbBack & "').sort("
  If isText Then
    sCommand = sCommand & ")"
  Else
    sCommand = sCommand & "function(a,b){return (a-b)})"
  End If
  If isDESC Then sCommand = sCommand & ".reverse()"
  sCommand = sCommand & ".join('" & vbBack & "')"
  With CreateObject("MSScriptControl.ScriptControl")
    .Language = "JavaScript"
    Sort1DArray = Split(.Eval(sCommand), vbBack)
  End With
End Function
PHP:
Function Sort2DArray(sArray, ColIndex As Long, Order As Boolean, HasTitle As Boolean)
  Dim TmpArr, Title, i As Long, j As Long, Dic, SortArr, SortArr2
  Dim Arr, iR As Long, Tmp, Chk As Boolean
  Set Dic = CreateObject("Scripting.Dictionary")
  On Error Resume Next
  TmpArr = sArray
  'Chk = IsNumeric(TmpArr(LBound(TmpArr, 1) - HasTitle, ColIndex))
  For i = LBound(TmpArr, 1) - HasTitle To UBound(TmpArr, 1)
    Tmp = TmpArr(i, ColIndex)
    If Dic.Exists(Tmp) Then
      Tmp = Tmp & vbTab & i
      TmpArr(i, ColIndex) = Tmp
    End If
    Dic.Add Tmp, i
  Next
  Arr = TmpArr
  SortArr = Sort1DArray(Dic.Keys, Not Chk, Order)
  For i = LBound(TmpArr, 1) - HasTitle To UBound(TmpArr, 1)
    iR = Dic.Item(SortArr(i + HasTitle - 1))
    For j = LBound(sArray, 2) To UBound(sArray, 2)
      Arr(i, j) = Replace(TmpArr(iR, j), vbTab & iR, "")
    Next
  Next
  Sort2DArray = Arr
End Function
Code thử nghiệm
PHP:
Sub TestHasTitle()
  Dim sArray, Arr
  sArray = Range("A1:C10000").Value
  Arr = Sort2DArray(sArray, 2, False, True)
  Range("E1:G10000").Value = Arr
End Sub
PHP:
Sub TestNoTitle()
  Dim sArray, Arr
  sArray = Range("A2:C10000").Value
  Arr = Sort2DArray(sArray, 2, False, False)
  Range("I2:K10000").Value = Arr
End Sub
Sort dữ liệu 10000 dòng, 3 cột, kết quả gần như nháy mắt
----------------------------------------
Tạm thời vẫn chưa biết cách nào để sort được các cột chứa Number (chỉ sort dạng Text mà thôi)
Các bạn down file về thử nghiệm và cải tiến giúp những chổ còn thiếu sót nhé. Cảm ơn
 

File đính kèm

  • Sort_2D_Array_01.rar
    123.9 KB · Đọc: 524
Đúng là cần phải cải tiến thêm rồi Thầy ơi, vì các lý do sau:
1) Kết quả xuất ra mất một Item, ngược lại double 1 đến 2 mục!
Hàm Sort2DArray đúng là bị dính chiêu này mà đến này mới biết sai chổ nào (sai ở 3 chổ)
Xin sửa lại như sau:

Mã:
Function Sort2DArray(ByVal sArray, ByVal ColIndex As Long, ByVal Order As Boolean, ByVal HasTitle As Boolean)
  Dim TmpArr, i As Long, j As Long, SortArr, Item1, Item2, firstVal As Double
  Dim Arr, iR As Long, Tmp(), n As Long, Chk As Boolean
  On Error Resume Next
  TmpArr = sArray: Arr = TmpArr
  ColIndex = ColIndex + LBound(TmpArr, 2) - 1
  firstVal = CDbl(TmpArr(LBound(TmpArr, 1) - HasTitle, ColIndex))
  Chk = firstVal > 0
  For i = LBound(TmpArr, 1) - HasTitle To UBound(TmpArr, 1)
[COLOR=#ff0000]    [B]ReDim Preserve Tmp(n)[/B][/COLOR]
    If Chk Then
      Tmp(n) = CDbl(TmpArr(i, ColIndex))
    Else
      Tmp(n) = CStr(TmpArr(i, ColIndex))
    End If
[COLOR=#ff0000]   [B] n = n + 1[/B][/COLOR]
  Next
  SortArr = Sort1DArray(Tmp, Not Chk, Order)
  With CreateObject("Scripting.Dictionary")
    For i = LBound(SortArr) To UBound(SortArr)
      If Chk Then
        If Not .Exists(CDbl(SortArr(i))) Then .Add CDbl(SortArr(i)), i [COLOR=#ff0000][B]+ LBound(TmpArr, 1) - HasTitle[/B][/COLOR]
      Else
        If Not .Exists(CStr(SortArr(i))) Then .Add CStr(SortArr(i)), i [COLOR=#ff0000][B]+ LBound(TmpArr, 1) - HasTitle[/B][/COLOR]
      End If
    Next
    For i = LBound(TmpArr, 1) - HasTitle To UBound(TmpArr, 1)
[B][COLOR=#ff0000]      If Chk Then[/COLOR][/B]
[B][COLOR=#ff0000]        iR = .Item(CDbl(TmpArr(i, ColIndex)))[/COLOR][/B]
[B][COLOR=#ff0000]      Else[/COLOR][/B]
[B][COLOR=#ff0000]        iR = .Item(CStr(TmpArr(i, ColIndex)))[/COLOR][/B]
[B][COLOR=#ff0000]      End If[/COLOR][/B]
      For j = LBound(TmpArr, 2) To UBound(TmpArr, 2)
        Arr(iR, j) = TmpArr(i, j)
      Next
[COLOR=#ff0000]      [B]If Chk Then[/B][/COLOR]
[COLOR=#ff0000][B]        .Item(CDbl(TmpArr(i, ColIndex))) = iR + 1[/B][/COLOR]
[COLOR=#ff0000][B]      Else[/B][/COLOR]
[COLOR=#ff0000][B]        .Item(CStr(TmpArr(i, ColIndex))) = iR + 1[/B][/COLOR]
[COLOR=#ff0000][B]      End If[/B][/COLOR]
    Next
  End With
  Sort2DArray = Arr
End Function
Các bạn test giúp tôi nhé (những chổ màu đò là những chổ đã chỉnh sửa)
 

File đính kèm

  • FilterAndSort_2DArray_02.rar
    42.7 KB · Đọc: 284
Upvote 0
Hàm Sort2DArray đúng là bị dính chiêu này mà đến này mới biết sai chổ nào (sai ở 3 chổ)
Xin sửa lại như sau:
Các bạn test giúp tôi nhé (những chổ màu đò là những chổ đã chỉnh sửa)
Cám ơn anhtuan1066 nhiều, tiện đây nhờ anhtuan viết luôn 1 UDF để lọc duy nhất theo 1 cột bất kỳ luôn.
Tựa như UniqueArr(sArr,ColIndex)
Cám ơn nhiều.
 
Upvote 0
Upvote 0
Hàm Sort2DArray đúng là bị dính chiêu này mà đến này mới biết sai chổ nào (sai ở 3 chổ)
Xin sửa lại như sau:


Các bạn test giúp tôi nhé (những chổ màu đò là những chổ đã chỉnh sửa)

Với hàm này, Thầy đã cải tiến được rất nhiều, không còn đúp hoặc sót mục nữa, sort cũng đã ngon lành hơn. Tuy nhiên, nếu đem so sánh với sort của excel thì vẫn chưa trật tự lắm. cụ thể là mình thử sửa vài mục thành a, b, c, ... 1, 2, 3 ... (mỗi hàng 1 ký tự chữ và 1 ký số) thì sẽ thấy nó vẫn chưa trật tự lắm. Ý nói rằng nó Sort theo từng cụm từ hay sao đấy! nhóm chuỗi gồm 1 ký tự thì tách riêng, nhóm 2 ký tự tách riêng v.v...

Nhưng hàm này cũng giải quyết được cơ bản nhiều vấn đề về xử lý chuỗi.

Cám ơn Thầy rất nhiều!
 
Chỉnh sửa lần cuối bởi điều hành viên:
Upvote 0
Function Sort2DArray(ByVal sArray, ByVal ColIndex As Long, ByVal Order As Boolean, ByVal HasTitle As Boolean)
Nhờ NDU giải thích cụ thể các tham số theo UDF trên.Trước mắt chỉ hiểu đượcByVal sArray: Mảng cần sortByVal ColIndex As Long: Sort theo cột ...Còn 2 tham số kia thì chưa hiểu lắm.Cám ơn!
 
Upvote 0
Với hàm này, Thầy đã cải tiến được rất nhiều, không còn đúp hoặc sót mục nữa, sort cũng đã ngon lành hơn. Tuy nhiên, nếu đem so sánh với sort của excel thì vẫn chưa trật tự lắm. cụ thể là mình thử sửa vài mục thành a, b, c, ... 1, 2, 3 ... (mỗi hàng 1 ký tự chữ và 1 ký số) thì sẽ thấy nó vẫn chưa trật tự lắm. Ý nói rằng nó Sort theo từng cụm từ hay sao đấy! nhóm chuỗi gồm 1 ký tự thì tách riêng, nhóm 2 ký tự tách riêng v.v...

Nhưng hàm này cũng giải quyết được cơ bản nhiều vấn đề về xử lý chuỗi.

Cám ơn Thầy rất nhiều!
Đã nói từ trước là chưa có khả năng sort dữ liệu chứa cà Number và Text mà ---> Nó dựa trên hàm Sort mảng 1 chiều và hàm này có có nhược điểm thế
Sắp tới tôi sẽ tính đến vấn đề này (thậm chí là sort luôn tiếng Việt Unicode)... Giải thuật đã có rồi, chỉ là.. hơi lười
Ẹc... Ẹc...
-------------------------------
Nhờ NDU giải thích cụ thể các tham số theo UDF trên.Trước mắt chỉ hiểu đượcByVal sArray: Mảng cần sortByVal ColIndex As Long: Sort theo cột ...Còn 2 tham số kia thì chưa hiểu lắm.Cám ơn!
Order là tùy chọn xem sort tăng hay giảm dần
HasTitle là tùy chọn xem dữ liệu có tiêu đề hay không
Giống như chức năng Sort của Excel thôi mà thunghi
 
Upvote 0
Đã nói từ trước là chưa có khả năng sort dữ liệu chứa cà Number và Text mà ---> Nó dựa trên hàm Sort mảng 1 chiều và hàm này có có nhược điểm thế
Sắp tới tôi sẽ tính đến vấn đề này (thậm chí là sort luôn tiếng Việt Unicode)... Giải thuật đã có rồi, chỉ là.. hơi lười
Ẹc... Ẹc...
-------------------------------

Order là tùy chọn xem sort tăng hay giảm dần
HasTitle là tùy chọn xem dữ liệu có tiêu đề hay không
Giống như chức năng Sort của Excel thôi mà thunghi
Code cuối cùng hoàn thiện nhất ở bài mấy vậy thầy? em thử dùng hết mấy code ở các bài mà nó cứ chạy ra sai sao ấy, chắc không biết dùng nên áp dụng sai quá
em cần nó chỉ sort thôi chứ không cần lọc, dữ liệu bị trùng nên dùng dic chắc không được.
 
Upvote 0
Mình nghĩ trong phần tìm kiếm textbox1 tìm kiếm được cả Machina name và tên máy nữa thì tuyệt.
Trước đây tôi có làm 1 form hổ trợ tìm kiếm và nhập liệu. Việc tìm kiếm thì dùng AutoFilter, còn sort dữ liệu trên ListBox thì đương nhiên dùng chức năng Sort sẳn có của Excel để làm: Sort trên bảng tính, xong gán dữ liệu từ bảng tính vào ListBox
Cảm thấy cách làm đó tuy đơn giản nhưng không mấy chuyên nghiệp, vả lại tốc độ xử lý cũng không cao!
Như ta đã biết, việc Filter đối với mảng 1 chiều thì đã có hàm Filter giải quyết. Vậy hôm nay tôi viết thêm hàm Filter2DArray nữa là có thể đưa vào ứng dụng với form hổ trợ tìm kiếm và nhập liệu rồi
Hàm Filter2DArray như sau:
PHP:
Function Filter2DArray(sArray, ColIndex As Long, FindStr As String)
  Dim TmpArr, i As Long, j As Long, Arr, Dic, TmpStr, Tmp
  Set Dic = CreateObject("Scripting.Dictionary")
  TmpArr = sArray
  ColIndex = ColIndex + LBound(TmpArr, 2) - 1
  For i = LBound(TmpArr, 1) To UBound(TmpArr, 1)
    TmpStr = Left(TmpArr(i, ColIndex), Len(FindStr))
    If UCase(TmpStr) = UCase(FindStr) Then Dic.Add i, ""
  Next
  If Dic.Count > 0 Then
    Tmp = Dic.Keys
    ReDim Arr(UBound(Tmp), LBound(TmpArr, 2) To UBound(TmpArr, 2))
    For i = LBound(Tmp) To UBound(Tmp)
      For j = LBound(TmpArr, 2) To UBound(TmpArr, 2)
        Arr(i, j) = TmpArr(Tmp(i), j)
      Next
    Next
  End If
  Filter2DArray = Arr
End Function
Vẫn sử dụng sự trợ giúp của Dictionary Object để định vị chỉ số dòng cần lấy ra kết quả
Giao diện Form như sau:

View attachment 61663

Với form này thì:
- Khi bấm vào các tiêu đề của ListBox thì dữ liệu sẽ được sort đúng tại cột này
- Gõ vài ký tự gợi nhớ vào TextBox thì List sẽ được thu gọn lại đúng với từ khóa tìm kiếm trên cột mà trước đó ta đã bấm (tức có thể tìm kiếm trên từng cột)
- Double Click vào 1 dòng nào đó trên ListBox, đồng nghĩa sẽ gán dữ liệu xuống bảng tính
-------------------------------------------
Vẫn là câu nói cũ: Cái khó ở đây là phải tính toán trên Array bất kể nó là Base 0 hay Base 1. Tức có thể làm việc với Range trên bảng tính (dùng Base 1) cũng như các mảng khác như ListBox chẳng hạn (dùng Base 0)
Xin các bạn vui lòng tải file về test giúp và góp ý để hoàn thiện hơn
Cảm ơn
ANH TUẤN
 
Upvote 0
Sao mình chạy hàm này nó không đưa lên vị trí đầu tiên của bảng
 
Upvote 0
Hàm Sort2DArray đúng là bị dính chiêu này mà đến này mới biết sai chổ nào (sai ở 3 chổ)
Xin sửa lại như sau:

Mã:
Function Sort2DArray(ByVal sArray, ByVal ColIndex As Long, ByVal Order As Boolean, ByVal HasTitle As Boolean)
  Dim TmpArr, i As Long, j As Long, SortArr, Item1, Item2, firstVal As Double
  Dim Arr, iR As Long, Tmp(), n As Long, Chk As Boolean
  On Error Resume Next
  TmpArr = sArray: Arr = TmpArr
  ColIndex = ColIndex + LBound(TmpArr, 2) - 1
  firstVal = CDbl(TmpArr(LBound(TmpArr, 1) - HasTitle, ColIndex))
  Chk = firstVal > 0
  For i = LBound(TmpArr, 1) - HasTitle To UBound(TmpArr, 1)
[COLOR=#ff0000]    [B]ReDim Preserve Tmp(n)[/B][/COLOR]
    If Chk Then
      Tmp(n) = CDbl(TmpArr(i, ColIndex))
    Else
      Tmp(n) = CStr(TmpArr(i, ColIndex))
    End If
[COLOR=#ff0000]   [B] n = n + 1[/B][/COLOR]
  Next
  SortArr = Sort1DArray(Tmp, Not Chk, Order)
  With CreateObject("Scripting.Dictionary")
    For i = LBound(SortArr) To UBound(SortArr)
      If Chk Then
        If Not .Exists(CDbl(SortArr(i))) Then .Add CDbl(SortArr(i)), i [COLOR=#ff0000][B]+ LBound(TmpArr, 1) - HasTitle[/B][/COLOR]
      Else
        If Not .Exists(CStr(SortArr(i))) Then .Add CStr(SortArr(i)), i [COLOR=#ff0000][B]+ LBound(TmpArr, 1) - HasTitle[/B][/COLOR]
      End If
    Next
    For i = LBound(TmpArr, 1) - HasTitle To UBound(TmpArr, 1)
[B][COLOR=#ff0000]      If Chk Then
        iR = .Item(CDbl(TmpArr(i, ColIndex)))
      Else
        iR = .Item(CStr(TmpArr(i, ColIndex)))
      End If[/COLOR][/B]
      For j = LBound(TmpArr, 2) To UBound(TmpArr, 2)
        Arr(iR, j) = TmpArr(i, j)
      Next
[COLOR=#ff0000]      [B]If Chk Then
        .Item(CDbl(TmpArr(i, ColIndex))) = iR + 1
      Else
        .Item(CStr(TmpArr(i, ColIndex))) = iR + 1
      End If[/B][/COLOR]
    Next
  End With
  Sort2DArray = Arr
End Function
Các bạn test giúp tôi nhé (những chổ màu đò là những chổ đã chỉnh sửa)
Anh anh chị giúp em, hàm này chỉ chạy trên Office 32 bit, còn với 64 bit thì không được ạ
 
Upvote 0
Upvote 0
Web KT

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

Back
Top Bottom