Sort trong mảng Arr

Liên hệ QC

NguyenthiH

Thành viên mới đăng ký
Tham gia
11/12/16
Bài viết
946
Được thích
172
Giới tính
Nữ
Em có file có dữ liệu Sheet1!A2:D, Thầy Ba Tê đã giúp em code lọc không trùng bằng DIC ra Mảng Arr, rồi nạp Mảng Arr đó vào ListBox, nhưng chưa Sort tăng dần. Bây giờ em muốn mọi người giúp em Sort mảng Arr tăng dần rồi nạp vào ListBox.
Em cám ơn.
ps: click C29 của sheet!Nhap sẽ hiện Form
 

File đính kèm

  • Book1.xlsb
    26.1 KB · Đọc: 33
Function Sort2DArray, dùng để sort theo 1 cột duy nhất
Source2D, dữ liệu nguồn nhiều dòng nhiều cột
HasTitle: Tiêu đề bảng, có tiêu đề: True, không có: False
ColIndex: thứ tự cột điều kiện Sort, đếm thứ tự từ cột đầu tiên (1, 2, 3 ....)
Order: Kiểu Sort, tăng dần: True, giảm dần: False
ShowTitle: Hiên tiêu đề bảng, cho hiện: True, không hiện: False

Function SortArray, dùng để sort theo tối đa theo 3 cột điều kiện
Mã:
Function Sort2DArray(ByVal Source2D, ByVal HasTitle As Boolean, ByVal ColIndex As Integer, _
        Optional ByVal Order As Boolean = True, Optional ByVal ShowTitle As Boolean = True)
'Sort theo 1 dieu kien, voi ColIndex là thu tu cot Sort dem tu cot dau tien
  Dim List As Object, Darr(), Arr(), SameArr(), tmp
  Dim i As Long, j As Long, idx As Long, lPos As Long
  Dim FistR As Integer, LastR As Long, FistC As Integer, LastC As Integer
  On Error GoTo Thoat
  Const Test_Source2D = 1
  If Test_Source2D = 2 Then
Thoat:
    MsgBox ("Source2D hoac các ColIndex khong dung" & Chr(13) & "Sort Data Khong duoc thuc hien")
    Sort2DArray = Source2D
    Exit Function
  End If
  Darr = Source2D
  FistR = LBound(Darr, 1): LastR = UBound(Darr, 1)
  FistC = LBound(Darr, 2): LastC = UBound(Darr, 2)
  Col = FistC + ColIndex - 1
  If HasTitle = False Then ShowTitle = True
  Set List = CreateObject("System.Collections.ArrayList")
  For i = FistR - HasTitle To LastR
    tmp = Darr(i, Col)
    If IsNumeric(tmp) Then tmp = CStr(String(15 - Len(CStr(tmp)), "0") & tmp)
    List.Add tmp
  Next
  List.Sort
  If Not Order Then List.Reverse
  If ShowTitle Then
    ReDim Arr(FistR To LastR, FistC To LastC)
    If HasTitle Then
      For j = FistC To LastC
        Arr(FistR, j) = Darr(FistR, j)
      Next j
    End If
  Else
    ReDim Arr(FistR To LastR + HasTitle, FistC To LastC)
  End If
  ReDim SameArr(List.Count - 1)
  For i = FistR - HasTitle To LastR
    tmp = Darr(i, Col)
    If IsNumeric(tmp) Then tmp = CStr(String(15 - Len(CStr(tmp)), "0") & tmp)
    idx = List.IndexOf(tmp, 0)
    lPos = idx + FistR + SameArr(idx)
    If ShowTitle Then lPos = lPos - HasTitle
    For j = FistC To LastC
      Arr(lPos, j) = Darr(i, j)
    Next
    SameArr(idx) = SameArr(idx) + 1
  Next
  Sort2DArray = Arr
  Set List = Nothing
End Function


Function SortArray(ByVal Source2D, ByVal HasTitle As Boolean, ByVal ColIndex1 As Integer, _
            Optional ByVal Order1 As Boolean = True, Optional ByVal ColIndex2 As Integer = -1245, _
            Optional ByVal Order2 As Boolean = True, Optional ByVal ColIndex3 As Integer = -1245, _
             Optional ByVal Order3 As Boolean = True, Optional ByVal ShowTitle As Boolean = True)
'Sort theo toi da 3 cot
  Dim Darr(), Scol As Integer
  On Error GoTo Thoat
  Const Test_Source2D = 1
  If Test_Source2D = 2 Then
Thoat:
    MsgBox ("Source2D hoac các ColIndex khong dung" & Chr(13) & "Sort Data Khong duoc thuc hien")
    SortArray = Source2D
    Exit Function
  End If
  Darr = Source2D
  Scol = UBound(Darr, 2) - LBound(Darr, 2) + 1  'So cot du lieu
  If ColIndex1 >= 1 And ColIndex1 <= Scol Then
    Darr = Sort2DArray(Darr, HasTitle, ColIndex1, Order1, ShowTitle)
    If ColIndex2 >= 1 Then
      If ColIndex2 <= Scol Then
        Darr = SortArray2Col(Darr, ColIndex1, ColIndex1, ColIndex2, Order2, HasTitle, ShowTitle)
        If ColIndex3 >= 1 And ColIndex3 <= Scol Then
          Darr = SortArray2Col(Darr, ColIndex1, ColIndex2, ColIndex3, Order3, HasTitle, ShowTitle)
        ElseIf ColIndex3 <> -1245 Then
          GoTo Thoat
        End If
      ElseIf ColIndex2 <> -1245 Then
        GoTo Thoat
      End If
    End If
    SortArray = Darr
  Else
    GoTo Thoat
  End If
End Function

Function SortArray2Col(ByVal Source2D, ByVal ColMain1 As Integer, ByVal ColMain2 As Integer, _
      ByVal ColIndex As Integer, ByVal Order As Boolean, ByVal HasTitle As Boolean, ByVal ShowTitle As Boolean)
  Dim Darr(), Arr()
  Dim i As Long, ir As Long, K As Long, StarR As Long, j As Integer, Tmp1, Tmp2
  Dim FistR As Integer, LastR As Long, FistC As Integer, LastC As Integer
  Darr = Source2D
  FistR = LBound(Darr, 1): LastR = UBound(Darr, 1)
  FistC = LBound(Darr, 2): LastC = UBound(Darr, 2)
  Col1 = FistC + ColMain1 - 1
  Col2 = FistC + ColMain2 - 1
  For i = FistR - HasTitle To LastR - 1
    If Darr(i, Col1) = Darr(i + 1, Col1) And Darr(i, Col2) = Darr(i + 1, Col2) Then
      StarR = i
      Tmp1 = Darr(i, Col1): Tmp2 = Darr(i, Col2)
      K = 0
      For ir = StarR To LastR
        If Darr(ir, Col1) = Tmp1 And Darr(ir, Col2) = Tmp2 Then
          K = K + 1
        Else
          Exit For
        End If
      Next ir
      ReDim Arr(1 To K, FistC To LastC)
      For ir = 1 To K
        For j = FistC To LastC
          Arr(ir, j) = Darr(StarR + ir - 1, j)
        Next j
      Next ir
      Arr = Sort2DArray(Arr, False, ColIndex, Order, True)
      For ir = 1 To K
        For j = FistC To LastC
          Darr(StarR + ir - 1, j) = Arr(ir, j)
        Next j
      Next ir
      i = i + K - 1
    End If
  Next i
  SortArray2Col = Darr
End Function
Các bạn góp ý dùm
 

File đính kèm

  • Sort_Array3.xlsm
    33.3 KB · Đọc: 19
Upvote 0
Code sắp xếp tiếng Việt không đúng.
Giả sử cột B có dữ liệu:
Đinh Công Tráng
Đinh Công Trẵng
Đinh Công Trấng
Đinh Công Trẳng
Đinh Công Trầng
Đinh Công Trặng
Đinh Công Trậng
Đinh Công Trâng
Đinh Công Trẫng
Đinh Công Trẩng
Đinh Công Tràng
Đinh Công Trằng
Đinh Công Trang
Đinh Công Trạng
Đinh Công Trăng
Đinh Công Trãng
Đinh Công Trảng
Đinh Công Trắng

Sau khi sắp xếp phải được: các dòng có a, à, ả, ã, á, ạ phải liền nhau.
Tức phải có
Đinh Công Trang
Đinh Công Tràng
Đinh Công Trảng
Đinh Công Trãng
Đinh Công Tráng
Đinh Công Trạng

Tương tự với các dòng có ă, ằ, ẳ, ẵ, ắ, ặ và các dòng có â, ầ, ẩ, ẫ, ấ, ậ

Code dùng ArrayList sắp xếp tiếng Việt không chuẩn.
 
Upvote 0
Function Sort2DArray, dùng để sort theo 1 cột duy nhất
Source2D, dữ liệu nguồn nhiều dòng nhiều cột
HasTitle: Tiêu đề bảng, có tiêu đề: True, không có: False
ColIndex: thứ tự cột điều kiện Sort, đếm thứ tự từ cột đầu tiên (1, 2, 3 ....)
Order: Kiểu Sort, tăng dần: True, giảm dần: False
ShowTitle: Hiên tiêu đề bảng, cho hiện: True, không hiện: False

Các bạn góp ý dùm

Tôi nghĩ bạn có thể cải tiến để chỉ còn lại 2 function: 1 function chính + 1 function phụ trợ. Tôi nghĩ như thế là đủ.
Thậm chí nếu khéo léo, muốn sort bao nhiêu cột cũng không có vấn đề chứ không chỉ giới hạn ở 3 cột đâu
 
Upvote 0
Code sắp xếp tiếng Việt không đúng.
Giả sử cột B có dữ liệu:
Đinh Công Tráng
Đinh Công Trẵng
Đinh Công Trấng
Đinh Công Trẳng
Đinh Công Trầng
Đinh Công Trặng
Đinh Công Trậng
Đinh Công Trâng
Đinh Công Trẫng
Đinh Công Trẩng
Đinh Công Tràng
Đinh Công Trằng
Đinh Công Trang
Đinh Công Trạng
Đinh Công Trăng
Đinh Công Trãng
Đinh Công Trảng
Đinh Công Trắng

Sau khi sắp xếp phải được: các dòng có a, à, ả, ã, á, ạ phải liền nhau.
Tức phải có
Đinh Công Trang
Đinh Công Tràng
Đinh Công Trảng
Đinh Công Trãng
Đinh Công Tráng
Đinh Công Trạng
Tương tự với các dòng có ă, ằ, ẳ, ẵ, ắ, ặ và các dòng có â, ầ, ẩ, ẫ, ấ, ậ
Code dùng ArrayList sắp xếp tiếng Việt không chuẩn.
ArrayLisst sort ra kết quả giống cụ sort của Excel, còn sort theo chuẩn tiếng Việt chắc phải thêm Function chuyển mã
 
Upvote 0
Tôi nghĩ bạn có thể cải tiến để chỉ còn lại 2 function: 1 function chính + 1 function phụ trợ. Tôi nghĩ như thế là đủ.
Thậm chí nếu khéo léo, muốn sort bao nhiêu cột cũng không có vấn đề chứ không chỉ giới hạn ở 3 cột đâu
mình sẽ cố thử xem được không
giới hạn số cột là do khai báo trong Function, có cách nào khai báo mà nhập bao nhiêu tham số cũng được không?như dạng
Mã:
Function SortArray(ByVal Source2D, ByVal HasTitle As Boolean, ByVal ColIndex1 As Integer, _
            Optional ByVal Order1 As Boolean = True, Optional ByVal ColIndex2 As Integer = -1245, Optional ByVal Order2 As Boolean = True, _
            ??? cái gì đó để không cần liệt kê đủ n cột bất kỳ chẳng hạn ??? _
            , Optional ByVal ShowTitle As Boolean = True)
nếu không có cách khai báo thì vẫn phải giới hạn số cột
 
Upvote 0
mình sẽ cố thử xem được không
giới hạn số cột là do khai báo trong Function, có cách nào khai báo mà nhập bao nhiêu tham số cũng được không?như dạng
Mã:
Function SortArray(ByVal Source2D, ByVal HasTitle As Boolean, ByVal ColIndex1 As Integer, _
            Optional ByVal Order1 As Boolean = True, Optional ByVal ColIndex2 As Integer = -1245, Optional ByVal Order2 As Boolean = True, _
            ??? cái gì đó để không cần liệt kê đủ n cột bất kỳ chẳng hạn ??? _
            , Optional ByVal ShowTitle As Boolean = True)
nếu không có cách khai báo thì vẫn phải giới hạn số cột

Tôi đang nghĩ đến hướng cho ColIndex và Order vào 1 Array, chẳng
Mã:
SortArray(Source2D, Array(5,2,3), Array(True, False, True))
Thì có nghĩa là sort 3 cột 5, 2, 3 theo kiểu Tăng, giảm, tăng (chẳng hạn)
 
Lần chỉnh sửa cuối:
Upvote 0
Tôi đang nghĩ đến hướng cho ColIndex và Order vào 1 Array, chẳng
Mã:
SortArray(Source2D, Array(5,2,3), Array(True, False, True))
Thì có nghĩa là sort 3 cột 5, 2, 3 theo kiểu Tăng, giảm, tăng (chẳng hạn)
theo gợi ý và code mẩu của bạn, mình tạo 3 function, trong đó TestSame có thể ghép vào còn 2 nhưng nhìn hơi rối và dài quá
Mã:
Function SortArray(ByVal Source2D, ByVal HasTitle As Boolean, ByVal ColIndex As Variant, _
             Optional ByVal Order As Variant = True, Optional ByVal ShowTitle As Boolean = True)
  Dim Darr(), Arr(), TmpArr(), Test_Source2D As Boolean
  Dim i As Long, ir As Long, k As Long, StarR As Long, j As Integer, C As Integer, Tmp
  Dim FistR As Integer, LastR As Long, FistC As Integer, LastC As Integer
  Darr = Source2D
  FistR = LBound(Darr, 1): LastR = UBound(Darr, 1)
  FistC = LBound(Darr, 2): LastC = UBound(Darr, 2)
  On Error GoTo Thoat
'Xet dieu kien chay Sort
  If Not IsArray(Darr) Then GoTo Thoat
  If LastR - FistR + 1 + HasTitle < 2 Then GoTo Thoat
  If IsArray(ColIndex) Then
      With CreateObject("scripting.dictionary")
        For k = LBound(ColIndex) To UBound(ColIndex)
          .Add ColIndex(k), ""
          If Not IsNumeric(ColIndex(k)) Then GoTo Thoat
          ColIndex(k) = ColIndex(k) + FistC - 1  'thu tu ColIndex theo column Darr
          If ColIndex(k) < LBound(Darr, 2) Or ColIndex(k) > UBound(Darr, 2) Then GoTo Thoat
        Next k
      End With
      If IsArray(Order) Then
        For k = LBound(ColIndex) To UBound(ColIndex)
          If k > UBound(Order) Or Order(k) <> False Then Order(k) = True
        Next k
      Else
        If Order = False Then Tmp = False Else Tmp = True
          ReDim Order(LBound(ColIndex) To UBound(ColIndex))
          For k = LBound(Order) To UBound(Order)
            Order(k) = Tmp
          Next k
      End If
  Else
    If Not IsNumeric(ColIndex) Or IsArray(Order) Then GoTo Thoat
    ColIndex = ColIndex + FistC - 1  'thu tu ColIndex theo column Darr
    If ColIndex < LBound(Darr) Or ColIndex > UBound(Darr) Then GoTo Thoat
    If Order <> False Then Order = True
    Darr = Sort2DArray(Darr, HasTitle, ColIndex, Order, ShowTitle)
  End If
  If IsArray(ColIndex) Then
    Darr = Sort2DArray(Darr, HasTitle, ColIndex(0), Order(0), ShowTitle)
    If UBound(ColIndex) - LBound(ColIndex) = 0 Then GoTo KetQua
    For C = LBound(ColIndex) + 1 To UBound(ColIndex)
      For i = FistR - HasTitle To LastR - 1
        If TestSame(Darr, ColIndex, i, C, 0) Then
          StarR = i
          k = 0
          For ir = StarR To LastR
            If TestSame(Darr, ColIndex, ir, C, i) Then
              k = k + 1
            Else
              Exit For
            End If
          Next ir
          ReDim Arr(1 To k, FistC To LastC)
          For ir = 1 To k
            For j = FistC To LastC
              Arr(ir, j) = Darr(StarR + ir - 1, j)
            Next j
          Next ir
          Arr = Sort2DArray(Arr, False, ColIndex(C), Order(C), True)
          For ir = 1 To k
            For j = FistC To LastC
              Darr(StarR + ir - 1, j) = Arr(ir, j)
            Next j
          Next ir
          i = i + k - 1
        End If
      Next i
    Next C
  End If
KetQua:
  SortArray = Darr
  Exit Function
  If Test_Source2D Then
Thoat:
    MsgBox ("Source2D hoac các ColIndex khong dung" & Chr(13) & "Sort Data Khong duoc thuc hien")
    SortArray = Source2D
    Exit Function
  End If
End Function
Mã:
Function Sort2DArray(ByVal Source2D, ByVal HasTitle As Boolean, ByVal ColIndex As Integer, _
        Optional ByVal Order As Boolean = True, Optional ByVal ShowTitle As Boolean = True)
'Sort theo 1 dieu kien, voi ColIndex là thu tu cot Sort dem tu cot dau tien
  Dim List As Object, Darr(), Arr(), SameArr(), Tmp
  Dim i As Long, j As Long, idx As Long, lPos As Long
  Dim FistR As Integer, LastR As Long, FistC As Integer, LastC As Integer
  'On Error GoTo Thoat
  Darr = Source2D
  FistR = LBound(Darr, 1): LastR = UBound(Darr, 1)
  FistC = LBound(Darr, 2): LastC = UBound(Darr, 2)
  If HasTitle = False Then ShowTitle = True
  Set List = CreateObject("System.Collections.ArrayList")
  For i = FistR - HasTitle To LastR
    Tmp = Darr(i, ColIndex)
    If IsNumeric(Tmp) Then Tmp = CStr(String(15 - Len(CStr(Tmp)), "0") & Tmp)
    List.Add Tmp
  Next
  List.Sort
  If Not Order Then List.Reverse
  If ShowTitle Then
    ReDim Arr(FistR To LastR, FistC To LastC)
    If HasTitle Then
      For j = FistC To LastC
        Arr(FistR, j) = Darr(FistR, j)
      Next j
    End If
  Else
    ReDim Arr(FistR To LastR + HasTitle, FistC To LastC)
  End If
  ReDim SameArr(List.Count - 1)
  For i = FistR - HasTitle To LastR
    Tmp = Darr(i, ColIndex)
    If IsNumeric(Tmp) Then Tmp = CStr(String(15 - Len(CStr(Tmp)), "0") & Tmp)
    idx = List.IndexOf(Tmp, 0)
    lPos = idx + FistR + SameArr(idx)
    If ShowTitle Then lPos = lPos - HasTitle
    For j = FistC To LastC
      Arr(lPos, j) = Darr(i, j)
    Next
    SameArr(idx) = SameArr(idx) + 1
  Next
  Sort2DArray = Arr
  Set List = Nothing
End Function
Mã:
Function TestSame(ByVal Darr, ByVal ColIndex, ByVal i, ByVal C, ByVal iC)
  Dim j As Integer, Col As Integer, Tmp
  TestSame = True
  For j = 0 To C - 1
    Col = ColIndex(j)
    If iC = 0 Then Tmp = Darr(i + 1, Col) Else Tmp = Darr(iC, Col)
    If Darr(i, Col) <> Tmp Then
      TestSame = False
      Exit Function
    End If
  Next j
End Function
 

File đính kèm

  • Sort_Array4.xlsm
    38 KB · Đọc: 53
Upvote 0
Chủ đề này không thấy tiếp tục, anh HieuCD có kết quả cuối cùng chưa?
Em đang muốn tìm cách sort nhiều cột trong mảng (tương tự add sort của excel) nhưng vẫn chưa tìm thấy, có ai đi ngang qua cho em xin một link, cảm ơn.
 
Upvote 0
Cái đó người ta dùng ArrayList và bản thân nó có chức năng này. Tuy nhiên, thấy dễ ăn vậy chứ thật ra chỉ áp dụng được bài của bạn, List đã được lọc duy nhất rồi nên sort xong còn "mò mò" ra được các phần tử ở cột khác chứ nếu để nguyên cái list chưa lọc duy nhất thì đố Arraylist mần được bài này
Mà cũng thấy lạ thật! Bạn HieuCD dùng ArrayList, bản thân nó cũng có chức năng lọc duy nhất, vậy sao phải thêm Dictionary vào chẳng hóa ra.. thừa???
----------------------
Tôi giải quyết bài toán theo hướng tổng quát: Mặc kệ danh sách có duy nhất hay không vẫn cứ sort được
1> Code trong Module:
Mã:
Function Sort2DArray(ByVal SourceArray, 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 = SourceArray: 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)
    ReDim Preserve tmp(n)
    If Chk Then
      tmp(n) = CDbl(tmpArr(i, ColIndex))
    Else
      tmp(n) = CStr(tmpArr(i, ColIndex))
    End If
    n = n + 1
  Next
  SortArr = Sort1DArray(tmp, 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 + LBound(tmpArr, 1) - HasTitle
      Else
        If Not .Exists(CStr(SortArr(i))) Then .Add CStr(SortArr(i)), i + LBound(tmpArr, 1) - HasTitle
      End If
    Next
    For i = LBound(tmpArr, 1) - HasTitle To UBound(tmpArr, 1)
      If Chk Then
        iR = .Item(CDbl(tmpArr(i, ColIndex)))
      Else
        iR = .Item(CStr(tmpArr(i, ColIndex)))
      End If
      For j = LBound(tmpArr, 2) To UBound(tmpArr, 2)
        Arr(iR, j) = tmpArr(i, j)
      Next
      If Chk Then
        .Item(CDbl(tmpArr(i, ColIndex))) = iR + 1
      Else
        .Item(CStr(tmpArr(i, ColIndex))) = iR + 1
      End If
    Next
  End With
  Sort2DArray = Arr
End Function
Function Sort1DArray(ByVal srcArr, ByVal Order As Boolean)
  Dim Item, tmpArr, Arr1, Arr2, n As Long, m As Long
  tmpArr = srcArr
  With CreateObject("System.Collections.ArrayList")
    For Each Item In tmpArr
      .Add Item
    Next
    .Sort
    Arr1 = .ToArray
    If Order = False Then
      ReDim Arr2(LBound(Arr1) To UBound(Arr1))
      For n = .Count To 1 Step -1
        Arr2(m) = Arr1(n - 1)
        m = m + 1
      Next
      Sort1DArray = Arr2
    Else
      Sort1DArray = Arr1
    End If
  End With
End Function
Function Unique2DArray(ByVal SourceArray, Optional ByVal ColIndex As Variant = 1)
  Dim aSrc, aCol, tmp As String, cItem
  Dim lR As Long, lC As Long, lUB1 As Long, lUB2 As Long, lLB1 As Long, lLB2 As Long, n As Long
  Dim dic As Object
  Set dic = CreateObject("Scripting.Dictionary")
  aSrc = SourceArray: aCol = ColIndex
  If Not IsArray(aCol) Then aCol = Array(aCol)
  lLB1 = LBound(aSrc, 1): lLB2 = LBound(aSrc, 2)
  lUB1 = UBound(aSrc, 1): lUB2 = UBound(aSrc, 2)
  ReDim aDes(1 To lUB2 + 1 - lLB2, 1 To 1)
  For lR = lLB1 To lUB1
    tmp = vbNullString
    If Len(CStr(aSrc(lR, 1))) Then
      For Each cItem In aCol
        tmp = tmp & vbBack & aSrc(lR, cItem)
      Next
      If Not dic.Exists(tmp) Then
        n = n + 1
        dic.Add tmp, lR
        ReDim Preserve aDes(1 To lUB2 + 1 - lLB2, 1 To n)
        For lC = lLB2 To lUB2
          aDes(lC, n) = aSrc(lR, lC)
        Next
      End If
    End If
  Next
  If n Then Unique2DArray = Transpose2DArray(aDes)
End Function
Function Transpose2DArray(ByVal SourceArray)
  Dim aSrc
  Dim lR As Long, lC As Long
  aSrc = SourceArray
  ReDim aDes(LBound(aSrc, 2) To UBound(aSrc, 2), LBound(aSrc, 1) To UBound(aSrc, 1))
  For lR = LBound(aSrc, 1) To UBound(aSrc, 1)
    For lC = LBound(aSrc, 2) To UBound(aSrc, 2)
      aDes(lC, lR) = aSrc(lR, lC)
    Next
  Next
  Transpose2DArray = aDes
End Function
2> Code trong Form:
Mã:
[COLOR=#ff0000]Private Sub Label1_Click()
  Dim aDes
  Static bChk As Boolean
  bChk = Not bChk
  aDes = Me.ListBox1.List
  aDes = Sort2DArray(aDes, 1, bChk, False)
  Me.ListBox1.List = aDes
End Sub
Private Sub Label2_Click()
  Dim aDes
  Static bChk As Boolean
  bChk = Not bChk
  aDes = Me.ListBox1.List
  aDes = Sort2DArray(aDes, 2, bChk, False)
  Me.ListBox1.List = aDes
End Sub
Private Sub UserForm_Initialize()
  Dim aSrc, aDes
  aSrc = Sheets("Nhap").Range("C2:D1000").Value
  aDes = Unique2DArray(aSrc, 1)
  ListBox1.List = aDes
End Sub[/COLOR]
Code trong Module tuy dài nhưng bạn mặc kệ nó đi, chỉ cần biết áp dụng hàm vào form là đủ (xem và khai triển chỗ màu đỏ là được rồi)
Lưu ý: Ở đây tôi viết cho bạn chức năng sort theo cách bạn bấm vào Label TÊN HÀNG hoặc ĐVT thì nó sẽ sort
Cám ơn thầy NDU
 
Upvote 0
Cái đó người ta dùng ArrayList và bản thân nó có chức năng này. Tuy nhiên, thấy dễ ăn vậy chứ thật ra chỉ áp dụng được bài của bạn, List đã được lọc duy nhất rồi nên sort xong còn "mò mò" ra được các phần tử ở cột khác chứ nếu để nguyên cái list chưa lọc duy nhất thì đố Arraylist mần được bài này
Mà cũng thấy lạ thật! Bạn HieuCD dùng ArrayList, bản thân nó cũng có chức năng lọc duy nhất, vậy sao phải thêm Dictionary vào chẳng hóa ra.. thừa???
----------------------
Tôi giải quyết bài toán theo hướng tổng quát: Mặc kệ danh sách có duy nhất hay không vẫn cứ sort được
1> Code trong Module:
Mã:
Function Sort2DArray(ByVal SourceArray, 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 = SourceArray: 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)
    ReDim Preserve tmp(n)
    If Chk Then
      tmp(n) = CDbl(tmpArr(i, ColIndex))
    Else
      tmp(n) = CStr(tmpArr(i, ColIndex))
    End If
    n = n + 1
  Next
  SortArr = Sort1DArray(tmp, 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 + LBound(tmpArr, 1) - HasTitle
      Else
        If Not .Exists(CStr(SortArr(i))) Then .Add CStr(SortArr(i)), i + LBound(tmpArr, 1) - HasTitle
      End If
    Next
    For i = LBound(tmpArr, 1) - HasTitle To UBound(tmpArr, 1)
      If Chk Then
        iR = .Item(CDbl(tmpArr(i, ColIndex)))
      Else
        iR = .Item(CStr(tmpArr(i, ColIndex)))
      End If
      For j = LBound(tmpArr, 2) To UBound(tmpArr, 2)
        Arr(iR, j) = tmpArr(i, j)
      Next
      If Chk Then
        .Item(CDbl(tmpArr(i, ColIndex))) = iR + 1
      Else
        .Item(CStr(tmpArr(i, ColIndex))) = iR + 1
      End If
    Next
  End With
  Sort2DArray = Arr
End Function
Function Sort1DArray(ByVal srcArr, ByVal Order As Boolean)
  Dim Item, tmpArr, Arr1, Arr2, n As Long, m As Long
  tmpArr = srcArr
  With CreateObject("System.Collections.ArrayList")
    For Each Item In tmpArr
      .Add Item
    Next
    .Sort
    Arr1 = .ToArray
    If Order = False Then
      ReDim Arr2(LBound(Arr1) To UBound(Arr1))
      For n = .Count To 1 Step -1
        Arr2(m) = Arr1(n - 1)
        m = m + 1
      Next
      Sort1DArray = Arr2
    Else
      Sort1DArray = Arr1
    End If
  End With
End Function
Function Unique2DArray(ByVal SourceArray, Optional ByVal ColIndex As Variant = 1)
  Dim aSrc, aCol, tmp As String, cItem
  Dim lR As Long, lC As Long, lUB1 As Long, lUB2 As Long, lLB1 As Long, lLB2 As Long, n As Long
  Dim dic As Object
  Set dic = CreateObject("Scripting.Dictionary")
  aSrc = SourceArray: aCol = ColIndex
  If Not IsArray(aCol) Then aCol = Array(aCol)
  lLB1 = LBound(aSrc, 1): lLB2 = LBound(aSrc, 2)
  lUB1 = UBound(aSrc, 1): lUB2 = UBound(aSrc, 2)
  ReDim aDes(1 To lUB2 + 1 - lLB2, 1 To 1)
  For lR = lLB1 To lUB1
    tmp = vbNullString
    If Len(CStr(aSrc(lR, 1))) Then
      For Each cItem In aCol
        tmp = tmp & vbBack & aSrc(lR, cItem)
      Next
      If Not dic.Exists(tmp) Then
        n = n + 1
        dic.Add tmp, lR
        ReDim Preserve aDes(1 To lUB2 + 1 - lLB2, 1 To n)
        For lC = lLB2 To lUB2
          aDes(lC, n) = aSrc(lR, lC)
        Next
      End If
    End If
  Next
  If n Then Unique2DArray = Transpose2DArray(aDes)
End Function
Function Transpose2DArray(ByVal SourceArray)
  Dim aSrc
  Dim lR As Long, lC As Long
  aSrc = SourceArray
  ReDim aDes(LBound(aSrc, 2) To UBound(aSrc, 2), LBound(aSrc, 1) To UBound(aSrc, 1))
  For lR = LBound(aSrc, 1) To UBound(aSrc, 1)
    For lC = LBound(aSrc, 2) To UBound(aSrc, 2)
      aDes(lC, lR) = aSrc(lR, lC)
    Next
  Next
  Transpose2DArray = aDes
End Function
2> Code trong Form:
Mã:
[COLOR=#ff0000]Private Sub Label1_Click()
  Dim aDes
  Static bChk As Boolean
  bChk = Not bChk
  aDes = Me.ListBox1.List
  aDes = Sort2DArray(aDes, 1, bChk, False)
  Me.ListBox1.List = aDes
End Sub
Private Sub Label2_Click()
  Dim aDes
  Static bChk As Boolean
  bChk = Not bChk
  aDes = Me.ListBox1.List
  aDes = Sort2DArray(aDes, 2, bChk, False)
  Me.ListBox1.List = aDes
End Sub
Private Sub UserForm_Initialize()
  Dim aSrc, aDes
  aSrc = Sheets("Nhap").Range("C2:D1000").Value
  aDes = Unique2DArray(aSrc, 1)
  ListBox1.List = aDes
End Sub[/COLOR]
Code trong Module tuy dài nhưng bạn mặc kệ nó đi, chỉ cần biết áp dụng hàm vào form là đủ (xem và khai triển chỗ màu đỏ là được rồi)
Lưu ý: Ở đây tôi viết cho bạn chức năng sort theo cách bạn bấm vào Label TÊN HÀNG hoặc ĐVT thì nó sẽ sort
Cái đó người ta dùng ArrayList và bản thân nó có chức năng này. Tuy nhiên, thấy dễ ăn vậy chứ thật ra chỉ áp dụng được bài của bạn, List đã được lọc duy nhất rồi nên sort xong còn "mò mò" ra được các phần tử ở cột khác chứ nếu để nguyên cái list chưa lọc duy nhất thì đố Arraylist mần được bài này
Mà cũng thấy lạ thật! Bạn HieuCD dùng ArrayList, bản thân nó cũng có chức năng lọc duy nhất, vậy sao phải thêm Dictionary vào chẳng hóa ra.. thừa???
----------------------
Tôi giải quyết bài toán theo hướng tổng quát: Mặc kệ danh sách có duy nhất hay không vẫn cứ sort được
1> Code trong Module:
Mã:
Function Sort2DArray(ByVal SourceArray, 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 = SourceArray: 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)
    ReDim Preserve tmp(n)
    If Chk Then
      tmp(n) = CDbl(tmpArr(i, ColIndex))
    Else
      tmp(n) = CStr(tmpArr(i, ColIndex))
    End If
    n = n + 1
  Next
  SortArr = Sort1DArray(tmp, 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 + LBound(tmpArr, 1) - HasTitle
      Else
        If Not .Exists(CStr(SortArr(i))) Then .Add CStr(SortArr(i)), i + LBound(tmpArr, 1) - HasTitle
      End If
    Next
    For i = LBound(tmpArr, 1) - HasTitle To UBound(tmpArr, 1)
      If Chk Then
        iR = .Item(CDbl(tmpArr(i, ColIndex)))
      Else
        iR = .Item(CStr(tmpArr(i, ColIndex)))
      End If
      For j = LBound(tmpArr, 2) To UBound(tmpArr, 2)
        Arr(iR, j) = tmpArr(i, j)
      Next
      If Chk Then
        .Item(CDbl(tmpArr(i, ColIndex))) = iR + 1
      Else
        .Item(CStr(tmpArr(i, ColIndex))) = iR + 1
      End If
    Next
  End With
  Sort2DArray = Arr
End Function
Function Sort1DArray(ByVal srcArr, ByVal Order As Boolean)
  Dim Item, tmpArr, Arr1, Arr2, n As Long, m As Long
  tmpArr = srcArr
  With CreateObject("System.Collections.ArrayList")
    For Each Item In tmpArr
      .Add Item
    Next
    .Sort
    Arr1 = .ToArray
    If Order = False Then
      ReDim Arr2(LBound(Arr1) To UBound(Arr1))
      For n = .Count To 1 Step -1
        Arr2(m) = Arr1(n - 1)
        m = m + 1
      Next
      Sort1DArray = Arr2
    Else
      Sort1DArray = Arr1
    End If
  End With
End Function
Function Unique2DArray(ByVal SourceArray, Optional ByVal ColIndex As Variant = 1)
  Dim aSrc, aCol, tmp As String, cItem
  Dim lR As Long, lC As Long, lUB1 As Long, lUB2 As Long, lLB1 As Long, lLB2 As Long, n As Long
  Dim dic As Object
  Set dic = CreateObject("Scripting.Dictionary")
  aSrc = SourceArray: aCol = ColIndex
  If Not IsArray(aCol) Then aCol = Array(aCol)
  lLB1 = LBound(aSrc, 1): lLB2 = LBound(aSrc, 2)
  lUB1 = UBound(aSrc, 1): lUB2 = UBound(aSrc, 2)
  ReDim aDes(1 To lUB2 + 1 - lLB2, 1 To 1)
  For lR = lLB1 To lUB1
    tmp = vbNullString
    If Len(CStr(aSrc(lR, 1))) Then
      For Each cItem In aCol
        tmp = tmp & vbBack & aSrc(lR, cItem)
      Next
      If Not dic.Exists(tmp) Then
        n = n + 1
        dic.Add tmp, lR
        ReDim Preserve aDes(1 To lUB2 + 1 - lLB2, 1 To n)
        For lC = lLB2 To lUB2
          aDes(lC, n) = aSrc(lR, lC)
        Next
      End If
    End If
  Next
  If n Then Unique2DArray = Transpose2DArray(aDes)
End Function
Function Transpose2DArray(ByVal SourceArray)
  Dim aSrc
  Dim lR As Long, lC As Long
  aSrc = SourceArray
  ReDim aDes(LBound(aSrc, 2) To UBound(aSrc, 2), LBound(aSrc, 1) To UBound(aSrc, 1))
  For lR = LBound(aSrc, 1) To UBound(aSrc, 1)
    For lC = LBound(aSrc, 2) To UBound(aSrc, 2)
      aDes(lC, lR) = aSrc(lR, lC)
    Next
  Next
  Transpose2DArray = aDes
End Function
2> Code trong Form:
Mã:
[COLOR=#ff0000]Private Sub Label1_Click()
  Dim aDes
  Static bChk As Boolean
  bChk = Not bChk
  aDes = Me.ListBox1.List
  aDes = Sort2DArray(aDes, 1, bChk, False)
  Me.ListBox1.List = aDes
End Sub
Private Sub Label2_Click()
  Dim aDes
  Static bChk As Boolean
  bChk = Not bChk
  aDes = Me.ListBox1.List
  aDes = Sort2DArray(aDes, 2, bChk, False)
  Me.ListBox1.List = aDes
End Sub
Private Sub UserForm_Initialize()
  Dim aSrc, aDes
  aSrc = Sheets("Nhap").Range("C2:D1000").Value
  aDes = Unique2DArray(aSrc, 1)
  ListBox1.List = aDes
End Sub[/COLOR]
Code trong Module tuy dài nhưng bạn mặc kệ nó đi, chỉ cần biết áp dụng hàm vào form là đủ (xem và khai triển chỗ màu đỏ là được rồi)
Lưu ý: Ở đây tôi viết cho bạn chức năng sort theo cách bạn bấm vào Label TÊN HÀNG hoặc ĐVT thì nó sẽ sort
Cám ơn anh ndu96081631, Hàm của anh đã giúp tôi rất nhiều trong công việc.
 
Upvote 0
Web KT
Back
Top Bottom