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
Trong Excel gọi là sort Ascending dù cho là text, number, date hay logic. Không gọi là tăng dần thì tôi cũng chả biết gọi sao.
Em thì hiểu từ ngữ đơn giản: Tăng dần tức là từ thấp tới cao, mà thấp với cao là đối chiếu với gốc quy ước để phân mức độ là thấp hay cao (nhỏ hay lớn), áp dụng với con số.

Trong chức năng Excel: "Sort A to Z" có ghi chú thêm "Lowest to highest".
Sort A to Z, tức là căn cứ vào thứ tự các chữ cái trong bảng chữ cái ABC (thứ tự này đã được quy ước chung) để sắp xếp.

Còn chủ thớt viết yêu cầu (bài #1):
nên em chỉ hiểu là áp dụng với con số.

Với trường hợp của chủ topic còn phải xem quy ước thứ tự sắp xếp là như nào: ký tự đặc biệt, số, chữ hoa, chữ thường...
 
Upvote 0
Em thì hiểu từ ngữ đơn giản: Tăng dần tức là từ thấp tới cao, mà thấp với cao là đối chiếu với gốc quy ước để phân mức độ là thấp hay cao (nhỏ hay lớn), áp dụng với con số.

Trong chức năng Excel: "Sort A to Z" có ghi chú thêm "Lowest to highest".
Sort A to Z, tức là căn cứ vào thứ tự các chữ cái trong bảng chữ cái ABC (thứ tự này đã được quy ước chung) để sắp xếp.

Lowest to highest = từ thấp đến cao, không tăng thì làm sao lên cao?
Bổ sung: Ascending và Descending là từ khóa sắp xếp trong VBA của Excel, xin lỗi bài trên nói không rõ.


Sort A to Z, tức là căn cứ vào thứ tự các chữ cái trong bảng chữ cái ABC (thứ tự này đã được quy ước chung) để sắp xếp.
Hai nút nhấn sort nhanh trên ribbon có biểu tượng AZ và ZA, dùng chung cho cả text và number chứ không riêng gì "bảng chữ cái ABC",

Còn thiếu sót của chủ topic chỉ là không nói sort cột nào thôi. Nếu nói rõ cột nào thì dù số hay text mọi người sẽ đều hiểu "tăng dần" là thế nào.
 
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???
dùng thêm Dictionary để ghi nhận item mãng 2 phần tử, sau nầy gán giá trị vào mãng Arr cho gọn, không cần phải split tách 2 phần tử
nếu list chứa các giá trị trùng lập thì làm cho nó không trùng lập bằng cách thêm 1 giá trị không trùng như thứ tự dòng chẳng hạn, lúc đó dùng thêm dictionary để lưu giá trị gốc vào Item, càng tiện lợi cho việc gán lại giá trị mãng
 
Upvote 0
@HieuCD:
Cải tiến code như vầy
Mã:
    Slist.Sort
    ReDim Arr(1 To k, 1 To 2)
    For i = 1 To k
      Tmp = .Item(Slist(i - 1))
      Arr(i, 1) = Tmp(0)
      Arr(i, 2) = Tmp(1)
    Next i
Theo như code nguyen thủy thì phải tra dic 2 lần cho mỗi key

Chú: nếu tôi là bạn thì tôi khong dùng cái biến Tmp. Lần thứ nhất, ở vòng lặp dựng lít, tôi dùng thẳng tên sortKey - vởi vì nó là cái key dùng để sort. Và lần thứ nhì, tức là ở tiểu đoạn code trên, tôi dùng tên listVals, hoặc myDat, myArr...
(Lưu ý là theo tinh thần code nguyên thủy của bạn thì Tmp luôn là sortKey)
 
Lần chỉnh sửa cuối:
Upvote 0
Nếu muốn cải tiến giải thuật đẻ không phải dùng dic thì bạn có thể làm như sau:

Nạp key1 + key2 + chỉ số dòng vào arraylist (đương nhiên số dòng phải theo định dạng 00001,... để dễ tách ra trở lại)
Sort ArayList
Duyệt list, dùng chỉ số dòng để lấy dữ liệu thẳng từ data array. Muốn duy nhất thì chỉ lấy key đầu, lướt qua các key lặp lại.
 
Upvote 0
@HieuCD:
Cải tiến code như vầy
Mã:
    Slist.Sort
    ReDim Arr(1 To k, 1 To 2)
    For i = 1 To k
      Tmp = .Item(Slist(i - 1))
      Arr(i, 1) = Tmp(0)
      Arr(i, 2) = Tmp(1)
    Next i
Theo như code nguyen thủy thì phải tra dic 2 lần cho mỗi key

Chú: nếu tôi là bạn thì tôi khong dùng cái biến Tmp. Lần thứ nhất, ở vòng lặp dựng lít, tôi dùng thẳng tên sortKey - vởi vì nó là cái key dùng để sort. Và lần thứ nhì, tức là ở tiểu đoạn code trên, tôi dùng tên listVals, hoặc myDat, myArr...
(Lưu ý là theo tinh thần code nguyên thủy của bạn thì Tmp luôn là sortKey)
cám ơn bạn, mình chỉnh lại code nhờ bạn góp ý thêm
Mã:
Private Sub Test()
Dim Sarr(), Darr(), Arr(), Slist As Object, ShortKey As String, myDat As Variant, i As Long, k As Long
Set Slist = CreateObject("System.Collections.ArrayList")
Darr = Sheets("Nhap").Range("C2:D" & Sheets("Nhap").Range("C65500").End(xlUp).Row).Value
With CreateObject("Scripting.Dictionary")
    For i = 1 To UBound(Darr)
        ShortKey = Darr(i, 1) & "#" & Darr(i, 2)
        If Not .Exists(ShortKey) Then
            .Add ShortKey, Array(Darr(i, 1), Darr(i, 2))
            Slist.Add ShortKey
        End If
    Next i
    Slist.Sort
    k = .Count
    ReDim Arr(1 To k, 1 To 2)
    For i = 1 To k
        myDat = .Item(Slist(i - 1))
        Arr(i, 1) = myDat(0)
        Arr(i, 2) = myDat(1)
    Next i
End With
End Sub
 
Upvote 0
dùng thêm Dictionary để ghi nhận item mãng 2 phần tử, sau nầy gán giá trị vào mãng Arr cho gọn, không cần phải split tách 2 phần tử
nếu list chứa các giá trị trùng lập thì làm cho nó không trùng lập bằng cách thêm 1 giá trị không trùng như thứ tự dòng chẳng hạn, lúc đó dùng thêm dictionary để lưu giá trị gốc vào Item, càng tiện lợi cho việc gán lại giá trị mãng

Ý tôi là bài này không cần đến Dictionary, chỉ với ArrayList tôi có thể vừa Unique vừa Sort ngon lành
(lưu ý rằng: Chỉ với bài này tôi chứ không phải bài toán tổng quát)
-----------------------------------
Bạn nghiên cứu xem!
 
Upvote 0
Em cứ tưởng Topic này dừng ở Bài #19 rồi chứ.
Không ngờ Topic này nhiều Cao Thủ vào xem và có thể còn nữa.
 
Upvote 0
Em cứ tưởng Topic này dừng ở Bài #19 rồi chứ.
Không ngờ Topic này nhiều Cao Thủ vào xem và có thể còn nữa.

Cái gì liên quan đến Sort mảng thì có thể bàn tiếp nha bạn!
Chuyện của bạn có thể xong nhưng người khác có thể bàn tiếp về giải thuật...
 
Upvote 0
Ý tôi là bài này không cần đến Dictionary, chỉ với ArrayList tôi có thể vừa Unique vừa Sort ngon lành
(lưu ý rằng: Chỉ với bài này tôi chứ không phải bài toán tổng quát)
-----------------------------------
Bạn nghiên cứu xem!
không tìm được cách
chỉ sort, nhưng dữ liệu bị trùng
Mã:
Private Sub Test1()
Dim Sarr(), Darr(), Arr(), Slist As Object, ShortKey As String, myDat As Variant, i As Long, k As Long
Set Slist = CreateObject("System.Collections.ArrayList")
Darr = Sheets("Nhap").Range("C2:D" & Sheets("Nhap").Range("C65500").End(xlUp).Row).Value
    For i = 1 To UBound(Darr)
        ShortKey = Darr(i, 1) & "#" & Darr(i, 2)
        Slist.Add ShortKey
    Next i
    Slist.Sort
    k = Slist.Count
    ReDim Arr(1 To k, 1 To 2)
    For i = 1 To k
        myDat = Split(Slist(i - 1), "#")
        Arr(i, 1) = myDat(0)
        Arr(i, 2) = myDat(1)
    Next i
    Range("G2").Resize(k, 2) = Arr
End Sub
 
Upvote 0
không tìm được cách
chỉ sort, nhưng dữ liệu bị trùng
Mã:
Private Sub Test1()
Dim Sarr(), Darr(), Arr(), Slist As Object, ShortKey As String, myDat As Variant, i As Long, k As Long
Set Slist = CreateObject("System.Collections.ArrayList")
Darr = Sheets("Nhap").Range("C2:D" & Sheets("Nhap").Range("C65500").End(xlUp).Row).Value
    For i = 1 To UBound(Darr)
        ShortKey = [COLOR=#ff0000]Darr(i, 1) & "#" & Darr(i, 2)[/COLOR]
        Slist.Add ShortKey
    Next i
    Slist.Sort
    k = Slist.Count
    ReDim Arr(1 To k, 1 To 2)
    For i = 1 To k
        myDat = Split(Slist(i - 1), "#")
        Arr(i, 1) = myDat(0)
        Arr(i, 2) = myDat(1)
    Next i
    Range("G2").Resize(k, 2) = Arr
End Sub
Gợi ý: Dùng phuong thức Contains để kiểm tra sự tồn tai (ví dụ If Not Slist.Contains(ShortKey) then....) giống phương thức Exists của Dictionary
Chỗ màu đỏ tôi không hiểu sao bạn lại nối chuỗi vậy nữa. Bởi:
- Thứ nhất: Nếu có vài chục cột thì nối đến bao giờ?
- Thứ hai: Người ta cần lọc duy nhất cột thứ nhất thì chỉ xét cột thứ nhất thôi chứ. Nối chuỗi vào như vậy là sai so với yêu cầu rồi
----------------------------------------
Lâu lắm rồi không dùng ArrayList, tự dưng nhắc lại cũng thấy.. ngứa nghề rồi đó nha... Ẹc... Ẹc...
 
Lần chỉnh sửa cuối:
Upvote 0
Gợi ý: Dùng phuong thức Contains để kiểm tra sự tồn tai (ví dụ If Not Slist.Contains(ShortKey) then....) giống phương thức Exists của Dictionary
Chỗ màu đỏ tôi không hiểu sao bạn lại nối chuỗi vậy nữa. Bởi:
- Thứ nhất: Nếu có vài chục cột thì nối đến bao giờ?
- Thứ hai: Người ta cần lọc duy nhất cột thứ nhất thì chỉ xét cột thứ nhất thôi chứ. Nối chuỗi vào như vậy là sai so với yêu cầu rồi
----------------------------------------
,Lâu lắm rồi không dùng ArrayList, tự dưng nhắc lại cũng thấy.. ngứa nghề rồi đó nha... Ẹc... Ẹc...
Cám ơn bạn, 2 sản phẩm cùng tên có thể có qui cách đơn vị tính khác nhau như bánh có thể là cái hoặc thùng, ngoài ra chưa biết cách gán giá trị Item đi theo Key để lấy đơn vị tính theo tên sản phẩm, bạn giúp dùm vấn đề nầy
 
Upvote 0
Cám ơn bạn, 2 sản phẩm cùng tên có thể có qui cách đơn vị tính khác nhau như bánh có thể là cái hoặc thùng
OK, đồng ý với bạn chỗ này!
ngoài ra chưa biết cách gán giá trị Item đi theo Key để lấy đơn vị tính theo tên sản phẩm, bạn giúp dùm vấn đề nầy
Xem code
Mã:
Private Sub UserForm_Initialize()
  Dim aSrc, aTmpArr, item, sTmp As String
  Dim oArrList As Object, oListOrigin As Object
  Dim lR As Long, n As Long, idx As Long
  aSrc = Sheets("Nhap").Range("C2:D1000").Value
  ReDim aTmpArr(1 To UBound(aSrc, 1), 1 To 2)
  Set oArrList = CreateObject("System.Collections.ArrayList")
  For lR = 1 To UBound(aSrc, 1)
    sTmp = CStr(aSrc(lR, 1))
    If Len(sTmp) Then
      If Not oArrList.Contains(sTmp) Then
        oArrList.Add sTmp
        n = n + 1
        aTmpArr(n, 1) = sTmp
        aTmpArr(n, 2) = aSrc(lR, 2)
      End If
    End If
  Next
  Set oListOrigin = oArrList.Clone
  oArrList.Sort
  ReDim aDes(1 To oArrList.Count, 1 To 2)
  For lR = 0 To oArrList.Count - 1
    idx = oListOrigin.InDexOf(oArrList(lR), 0) + 1
    aDes(lR + 1, 1) = aTmpArr(idx, 1)
    aDes(lR + 1, 2) = aTmpArr(idx, 2)
  Next
  Me.ListBox1.List = aDes
End Sub
Còn thắc mắc thì ta... tiếp tục
 
Upvote 0
OK, đồng ý với bạn chỗ này!

Xem code
Mã:
Private Sub UserForm_Initialize()
  Dim aSrc, aTmpArr, item, sTmp As String
  Dim oArrList As Object, oListOrigin As Object
  Dim lR As Long, n As Long, idx As Long
  aSrc = Sheets("Nhap").Range("C2:D1000").Value
  ReDim aTmpArr(1 To UBound(aSrc, 1), 1 To 2)
  Set oArrList = CreateObject("System.Collections.ArrayList")
  For lR = 1 To UBound(aSrc, 1)
    sTmp = CStr(aSrc(lR, 1))
    If Len(sTmp) Then
      If Not oArrList.Contains(sTmp) Then
        oArrList.Add sTmp
        n = n + 1
        aTmpArr(n, 1) = sTmp
        aTmpArr(n, 2) = aSrc(lR, 2)
      End If
    End If
  Next
  Set oListOrigin = oArrList.Clone
  oArrList.Sort
  ReDim aDes(1 To oArrList.Count, 1 To 2)
  For lR = 0 To oArrList.Count - 1
    idx = oListOrigin.InDexOf(oArrList(lR), 0) + 1
    aDes(lR + 1, 1) = aTmpArr(idx, 1)
    aDes(lR + 1, 2) = aTmpArr(idx, 2)
  Next
  Me.ListBox1.List = aDes
End Sub
Còn thắc mắc thì ta... tiếp tục
Code của anh hay qúa trời luôn
em sửa mãi mới ra được đoạn code thì đã muộn rồi.
PHP:
Sub Test2()
Dim Sarr(), Darr(), arr(), tpm(), Slist As Object, myDat As Variant, i As Long, k As Long
Dim ShortKey As String
Set Slist = CreateObject("System.Collections.ArrayList")
Darr = Sheets("Nhap").Range("C2:D" & Sheets("Nhap").Range("C65500").End(xlUp).Row).Value
    For i = 1 To UBound(Darr)
        ShortKey = Darr(i, 1) & "#" & Darr(i, 2)
        If Not Slist.Contains(ShortKey) Then
            Slist.Add ShortKey
        End If
    Next i
    Slist.Sort
    k = Slist.Count
    ReDim arr(1 To k, 1 To 2)
    tpm = Slist.toarray()
    For i = 0 To k - 1
        arr(i + 1, 1) = Left(tpm(i), InStr(tpm(i), "#") - 1)
        arr(i + 1, 2) = Right(tpm(i), Len(tpm(i)) - InStr(tpm(i), "#"))
    Next
   Sheet1.Range("K1").Resize(k, 2) = arr
End Sub
 
Upvote 0
OK, đồng ý với bạn chỗ này!

Xem code
Mã:
Private Sub UserForm_Initialize()
  Dim aSrc, aTmpArr, item, sTmp As String
  Dim oArrList As Object, oListOrigin As Object
  Dim lR As Long, n As Long, idx As Long
  aSrc = Sheets("Nhap").Range("C2:D1000").Value
  ReDim aTmpArr(1 To UBound(aSrc, 1), 1 To 2)
  Set oArrList = CreateObject("System.Collections.ArrayList")
  For lR = 1 To UBound(aSrc, 1)
    sTmp = CStr(aSrc(lR, 1))
    If Len(sTmp) Then
      If Not oArrList.Contains(sTmp) Then
        oArrList.Add sTmp
        n = n + 1
        aTmpArr(n, 1) = sTmp
        aTmpArr(n, 2) = aSrc(lR, 2)
      End If
    End If
  Next
  Set oListOrigin = oArrList.Clone
  oArrList.Sort
  ReDim aDes(1 To oArrList.Count, 1 To 2)
  For lR = 0 To oArrList.Count - 1
    idx = oListOrigin.InDexOf(oArrList(lR), 0) + 1
    aDes(lR + 1, 1) = aTmpArr(idx, 1)
    aDes(lR + 1, 2) = aTmpArr(idx, 2)
  Next
  Me.ListBox1.List = aDes
End Sub
Còn thắc mắc thì ta... tiếp tục
cám ơn bạn, biết thêm một số lệnh hay
thêm 1 arraylist để ghi nhận 1 Item, nếu nhiều dữ liệu lưu theo Key thì dùng thứ tự dòng làm Item, bạn góp ý dùm
Mã:
Private Sub UserForm_Initialize()
  Dim aSrc, aTmpArr, sTmp As String
  Dim sList As Object, oList1 As Object, oList2 As Object
  Dim lR As Long, idx As Long
  aSrc = Sheets("Nhap").Range("C2:D1000").Value
  Set oList1 = CreateObject("System.Collections.ArrayList")
  Set oList2 = CreateObject("System.Collections.ArrayList")
  For lR = 1 To UBound(aSrc, 1)
    sTmp = CStr(aSrc(lR, 1))
    If Len(sTmp) Then
      If Not oList1.Contains(sTmp) Then
        oList1.Add sTmp
            [COLOR=#0000cd]oList2.Add CStr(aSrc(lR, 2))
            'oList2.Add lR[/COLOR]
      End If
    End If
  Next
  Set sList = oList1.Clone
  sList.Sort
  ReDim aDes(1 To sList.Count, 1 To 2)
  For lR = 0 To sList.Count - 1
    idx = oList1.InDexOf(sList(lR), 0)
[COLOR=#0000cd]        aDes(lR + 1, 1) = oList1(idx)
        aDes(lR + 1, 2) = oList2(idx)
        'idx = oList2(idx)
        'aDes(lR + 1, 1) = aSrc(idx, 1)
        'aDes(lR + 1, 2) = aSrc(idx, 2)[/COLOR]
  Next
  Me.ListBox1.List = aDes
End Sub
 
Upvote 0
cám ơn bạn, biết thêm một số lệnh hay
thêm 1 arraylist để ghi nhận 1 Item, nếu nhiều dữ liệu lưu theo Key thì dùng thứ tự dòng làm Item, bạn góp ý dùm
Mã:
Private Sub UserForm_Initialize()
  Dim aSrc, aTmpArr, sTmp As String
  Dim sList As Object, oList1 As Object, oList2 As Object
  Dim lR As Long, idx As Long
  aSrc = Sheets("Nhap").Range("C2:D1000").Value
  Set oList1 = CreateObject("System.Collections.ArrayList")
  Set oList2 = CreateObject("System.Collections.ArrayList")
  For lR = 1 To UBound(aSrc, 1)
    sTmp = CStr(aSrc(lR, 1))
    If Len(sTmp) Then
      If Not oList1.Contains(sTmp) Then
        oList1.Add sTmp
            [COLOR=#0000cd]oList2.Add CStr(aSrc(lR, 2))
            'oList2.Add lR[/COLOR]
      End If
    End If
  Next
  Set sList = oList1.Clone
  sList.Sort
  ReDim aDes(1 To sList.Count, 1 To 2)
  For lR = 0 To sList.Count - 1
    idx = oList1.InDexOf(sList(lR), 0)
[COLOR=#0000cd]        aDes(lR + 1, 1) = oList1(idx)
        aDes(lR + 1, 2) = oList2(idx)
        'idx = oList2(idx)
        'aDes(lR + 1, 1) = aSrc(idx, 1)
        'aDes(lR + 1, 2) = aSrc(idx, 2)[/COLOR]
  Next
  Me.ListBox1.List = aDes
End Sub

Nhìn chung là ổn!
Trong code của bạn có oList1, oList2 và sList... cả 3 đều là ArrayList. Giải quyết bài này mà dùng đến 3 object thì thôi tôi thà dùng ArrayList + Dictionary sướng hơn
Nói vui thế thôi chứ các bạn tham gia là tôi vui rồi. Mong có dịp học hỏi thêm từ các bạn
 
Upvote 0
thêm 1 arraylist để ghi nhận 1 Item, nếu nhiều dữ liệu lưu theo Key thì dùng thứ tự dòng làm Item, bạn góp ý dùm

Bạn không cần phải dùng nhiều list như thế. Chỉ cần 1
Khi ghi key, cần ghi 2 lần. Lần thứ nhất là key nguyên vẹn, dùng để kiểm tra với hàm Contains. Lần thứ nhì là key cộng số row trong mảng, túc là key & Right(Cstr(1000000+lR),6)

Đương nhiên List của bạn sẽ lớn gấp 2 lần bình thường. Nhưng khong sao cả, arraylist là class của dot net, chúng tự biết chọn cách sort rất hiệu quả.

Sau khi sort xong, bạn sẽ có list sắp theo thứ tự. Những phần tử vị trí chẵn (0, 2, 4...) là key nguyên thuỷ, bạn lướt qua. Phần tử lẻ (1, 3,...) là key và chỉ số dòng trong mảng. Bạn chỉ cần tách ra Val(Right(key,6)) và dùng nó để lấy dữ liệu trong mảng.

=== Bổ sung ===
Quên mất, chơi trò sort mà ghép chuỗi suông thì sẽ bị kết quả bất ngờ nếu gặp trường hợp key này chứa key kia
"abc def" chứa "abc"; khi nối thêm chuỗi vào, "abc def005" sẽ được sort ra trước "abc002"
Khi sort chuỗi ghép, luôn luôn chèn thêm ký tự null. Lúc ấy chuỗi con sẽ bảo đảm được sort trước chuỗi mẹ.
==> key & vbNullChar & Right(Cstr(1000000+lR),6)
(nếu dùng Unicode thì dùng 2 ký tự cho chắc ăn)
 
Lần chỉnh sửa cuối:
Upvote 0
Bạn không cần phải dùng nhiều list như thế. Chỉ cần 1
Khi ghi key, cần ghi 2 lần. Lần thứ nhất là key nguyên vẹn, dùng để kiểm tra với hàm Contains. Lần thứ nhì là key cộng số row trong mảng, túc là key & Right(Cstr(1000000+lR),6)
Đương nhiên List của bạn sẽ lớn gấp 2 lần bình thường. Nhưng khong sao cả, arraylist là class của dot net, chúng tự biết chọn cách sort rất hiệu quả.
Sau khi sort xong, bạn sẽ có list sắp theo thứ tự. Những phần tử vị trí chẵn (0, 2, 4...) là key nguyên thuỷ, bạn lướt qua. Phần tử lẻ (1, 3,...) là key và chỉ số dòng trong mảng. Bạn chỉ cần tách ra Val(Right(key,6)) và dùng nó để lấy dữ liệu trong mảng.
cám ơn bạn, cách nầy rất tuyệt, vậy là bài toán đã giải quyết triệt để
 
Upvote 0
Ai rảnh nghiên cứu thử dùng ArrayList để sort mảng 2 chiều xem. Đương nhiên mảng 2 chiều ở đây là mảng tùy ý (không phải đã lọc duy nhất như bài toán ở topic này)
Tôi chưa làm nhưng tôi cảm giác là được. Ngoài ArrayList, có thể dùng SortedList, Stack... hay gì gì đó tương tự cũng được
(vấn đề của tôi là thời gian rảnh ít quá, chưa thể bắt tay làm một cách nghiêm túc được)
 
Upvote 0
Ai rảnh nghiên cứu thử dùng ArrayList để sort mảng 2 chiều xem. Đương nhiên mảng 2 chiều ở đây là mảng tùy ý (không phải đã lọc duy nhất như bài toán ở topic này)
Tôi chưa làm nhưng tôi cảm giác là được. Ngoài ArrayList, có thể dùng SortedList, Stack... hay gì gì đó tương tự cũng được
(vấn đề của tôi là thời gian rảnh ít quá, chưa thể bắt tay làm một cách nghiêm túc được)
dùng ArrayList sort mảng 2 chiều theo tối đa 3 điều kiện, chắc còn sơ sót các bạn góp ý thêm, chạy sub main để kiểm tra
Mã:
Sub Main()
Dim Darr()
Darr = Range("A1:E" & Range("B" & Rows.Count).End(xlUp).Row).Value
Arr = SortArray(Darr, True, 2, True, 3, True, 4, True)
Range("G1").Resize(UBound(Darr), UBound(Darr, 2)) = Arr
End Sub

Function SortArray(ByVal SourceArray, ByVal HasTitle As Boolean, ByVal ColIndex1 As Byte, _
            Optional ByVal Order1 As Boolean = True, Optional ByVal ColIndex2 As Byte = 0, _
            Optional ByVal Order2 As Boolean = True, Optional ByVal ColIndex3 As Byte = 0, _
             Optional ByVal Order3 As Boolean = True)
  Dim Darr(), Arr()
  Dim i As Long, iP As Long, ir As Long, k As Long, R As Long, LenR As Byte, Tmp
  Darr = SourceArray
  ReDim Arr(1 To UBound(Darr), 1 To UBound(Darr, 2))
  If ColIndex1 >= 1 And ColIndex1 <= UBound(Darr, 2) Then
    If ColIndex2 = 0 Then
      Arr = SortArray1Col(Darr, ColIndex1, Order1, HasTitle, True)
    Else
      Arr = SortArray1Col(Darr, ColIndex1, Order1, HasTitle)
      If ColIndex2 >= 1 And ColIndex2 <= UBound(Darr, 2) Then
        Darr = Arr
        Arr = SortArray2Col(Darr, ColIndex1, ColIndex2, Order2, HasTitle)
        If ColIndex3 >= 1 And ColIndex3 <= UBound(Darr, 2) Then
          Darr = Arr
          Arr = SortArray2Col(Darr, ColIndex2, ColIndex3, Order3, HasTitle)
        End If
      End If
    End If
    SortArray = Arr
  End If
End Function

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)
  Dim IndexList As Object, List As Object, Darr(), Arr()
  Dim i As Long, j As Byte, k As Long, R As Long, LenR As Integer, Tmp
  Set IndexList = CreateObject("System.Collections.ArrayList")
  Darr = SourceArray
  R = UBound(Darr) + HasTitle 'so dong du lieu Sort
  LenR = Len(CStr(R))         'so chu so cua thu tu dong
  If ColIndex < 1 Or ColIndex > UBound(Darr, 2) Then
    MsgBox ("ColIndex khong phu hop" & Chr(13) & "Sort Data Khong duoc thuc hien")
    SortArray1Col = Darr
    Exit Function
  End If
  For i = 1 To R
    Tmp = Darr(i - HasTitle, ColIndex)
    If IsNumeric(Tmp) Then Tmp = CStr(String(15 - Len(CStr(Tmp)), "0") & Tmp)
    Tmp = Tmp & String(LenR - Len(CStr(i)), "0") & i
    IndexList.Add Tmp
  Next
  Set List = IndexList.Clone
  List.Sort
  ReDim Arr(1 To UBound(Darr), 1 To UBound(Darr, 2))
  If HasTitle = False Then HideTitle = False
  If HideTitle Then
    ReDim Arr(1 To R, 1 To UBound(Darr, 2))
  Else
    ReDim Arr(1 To UBound(Darr), 1 To UBound(Darr, 2))
    If HasTitle Then
      For j = 1 To UBound(Darr, 2)
        Arr(1, j) = Darr(1, j)
      Next j
    End If
  End If
  For i = 0 To R - 1
    k = IndexList.InDexOf(List(i), 0) + 1
    For j = 1 To UBound(Darr, 2)
      If Order Then n = i + 1 Else n = R - i
      If HideTitle Then
        Arr(n, j) = Darr(k - HasTitle, j)
      Else
        Arr(n - HasTitle, j) = Darr(k - HasTitle, j)
      End If
    Next j
  Next i
  SortArray1Col = Arr
End Function

Function SortArray2Col(ByVal SourceArray, ByVal ColMain As Byte, ByVal ColIndex As Byte, ByVal Order As Boolean, Optional ByVal HasTitle As Boolean = False)
  Dim Darr(), Arr()
  Dim i As Long, ir As Long, k As Long, R As Long, j As Integer, Tmp
  Darr = SourceArray
  For i = 1 - HasTitle To UBound(Darr) - 1
    If Darr(i, ColMain) = Darr(i + 1, ColMain) Then
      R = i
      Tmp = Darr(i, ColMain)
      k = 0
      For ir = R To UBound(Darr)
        If Darr(ir, ColMain) = Tmp Then
          k = k + 1
        Else
          Exit For
        End If
      Next ir
      ReDim Arr(1 To k, 1 To UBound(Darr, 2))
      For ir = 1 To k
        For j = 1 To UBound(Darr, 2)
          Arr(ir, j) = Darr(ir + R - 1, j)
        Next j
      Next ir
      Arr = SortArray1Col(Arr, ColIndex, Order)
      For ir = 1 To k
        For j = 1 To UBound(Darr, 2)
          Darr(ir + R - 1, j) = Arr(ir, j)
        Next j
      Next ir
      i = i + k - 1
    End If
  Next i
  SortArray2Col = Darr
End Function
 

File đính kèm

  • Sort_Array.xlsb
    26.1 KB · Đọc: 27
Upvote 0
Web KT
Back
Top Bottom