Tặng các bạn thủ tục sort trong mảng 2 chiều, có tuỳ chọn thứ tự cột ưu tiên (2 người xem)

Người dùng đang xem chủ đề này

Quang_Hải

Thành viên gạo cội
Tham gia
21/2/09
Bài viết
6,077
Được thích
8,011
Nghề nghiệp
Làm đủ thứ
Công cụ sẵn có của Excel để sort thì không thể bàn cãi thêm.
Tuy nhiên có lẽ có lúc chúng ta cần thực hiện Sort trong mảng 2 chiều và cần ưu tiên chọn cột để đưa kết quả vào 1 ListBox. Qua những kiến thức đã học được từ diễn đàn GPE, mình đã cố gắng mày mò và cuối cùng cũng cho ra được 1 thủ tục Sort trong mảng 2 chiều. Hy vọng từ thủ tục này, các bạn sẽ bổ sung những điểm còn hạn chế để cho ra 1 thủ tục hoàn chỉnh hơn.
Các bạn có thể thêm bớt thay đổi ưu tiên số cột cần sort trong dòng code:
SortOrder = Array(1, 2, 3, 6)
PHP:
Sub ArraySort()
'Written by QuangHai
Dim Data(), Temp As String
Dim FirsrtRow As Long, FirstCol As String, SortOrder()
Dim TotalCols As Byte, Row As Long, J As Long
SortOrder = Array(1, 2, 3, 6)
With Sheets("Nguon")
   Data = .Range("A3", .[M65536].End(3)).Value
End With
TotalCols = UBound(Data, 2)
ReDim Preserve Data(1 To UBound(Data), 1 To (TotalCols + 1))
For Row = 1 To UBound(Data, 1)
   For J = 0 To UBound(SortOrder)
      If IsDate(Data(Row, SortOrder(J))) Then
         Temp = Temp & CLng(Data(Row, SortOrder(J)))
      Else
         Temp = Temp & Format(Data(Row, SortOrder(J)), String(15, "0"))
      End If
   Next
   Data(Row, TotalCols + 1) = Temp
   Temp = Empty
Next
QuickSort Data, LBound(Data), UBound(Data)
Sheets("Dich").[A3].Resize(UBound(Data), TotalCols) = Data
End Sub
PHP:
Sub QuickSort(Arr(), Min As Long, Max As Long)
  Dim MidVal As Variant, TempVal As Variant
  Dim TempMin&, TempMax&, LastCol&, TotalCol&
  TempMin = Min
  TempMax = Max
  LastCol = UBound(Arr, 2)
  MidVal = Arr((Min + Max) \ 2, LastCol)
  Do While TempMin <= TempMax
    Do While Arr(TempMin, LastCol) < MidVal And TempMin < Max
      TempMin = TempMin + 1
    Loop
    Do While MidVal < Arr(TempMax, LastCol) And TempMax > Min
      TempMax = TempMax - 1
    Loop
    If TempMin <= TempMax Then
      For TotalCol = 1 To LastCol
         TempVal = Arr(TempMin, TotalCol)
         Arr(TempMin, TotalCol) = Arr(TempMax, TotalCol)
         Arr(TempMax, TotalCol) = TempVal
      Next
      TempMin = TempMin + 1
      TempMax = TempMax - 1
    End If
  Loop
  If Min < TempMax Then QuickSort Arr, Min, TempMax
  If TempMin < Max Then QuickSort Arr, TempMin, Max
End Sub
 

File đính kèm

Code của bác nếu sắp xếp cột toàn số hoặc toàn date thì đúng. Vì excel lưu định dạng date dưới dạng số (ví dụ: ngày 25/11/2014 excel sẽ lưu là 41968, lệnh format(data(...),string(15,"0")) sẽ ra kết quả 000000000041968) nên có thể không cần if isdate(data(...)).

Nhưng nếu sắp xếp ô string sẽ không chính xác. Khi so sánh string: "a" <"a b" nhưng "a1">"a b1". Vì vậy nếu có 2 người "Bùi Thị Lùn" và "Bùi Thị Lùn Tịt" thì nếu chỉ sort 1 cột sẽ ra kết quả "Bùi Thị Lùn" đứng trước "Bùi Thị Lùn Tịt" nhưng kết hợp thêm cột số sẽ ra kết quả ngược lại. Để khắc phục vấn đề này có thể trước mỗi lần nối chuỗi vào biến temp ta thêm space vào cuối. Khi đó "a"<"a b" và "a 1"<"a b 1" nên có thể sẽ ra kết quả đúng (bác kiểm tra lại xem còn khả năng nào sai không?). Tuy nhiên kể cả như vậy sort tiếng Việt vẫn chưa đúng.
 
Lần chỉnh sửa cuối:
Upvote 0
Code của bác nếu sắp xếp cột toàn số hoặc toàn date thì đúng. Vì excel lưu định dạng date dưới dạng số (ví dụ: ngày 25/11/2014 excel sẽ lưu là 41968, lệnh format(data(...),string(15,"0")) sẽ ra kết quả 000000000041968) nên có thể không cần if isdate(data(...)).

Nhưng nếu sắp xếp ô string sẽ không chính xác. Khi so sánh string: "a" <"a b" nhưng "a1">"a b1". Vì vậy nếu có 2 người "Bùi Thị Lùn" và "Bùi Thị Lùn Tịt" thì nếu chỉ sort 1 cột sẽ ra kết quả "Bùi Thị Lùn" đứng trước "Bùi Thị Lùn Tịt" nhưng kết hợp thêm cột số sẽ ra kết quả ngược lại. Để khắc phục vấn đề này có thể trước mỗi lần nối chuỗi vào biến temp ta thêm space vào cuối. Khi đó "a"<"a b" và "a 1"<"a b 1" nên có thể sẽ ra kết quả đúng (bác kiểm tra lại xem còn khả năng nào sai không?). Tuy nhiên kể cả như vậy sort tiếng Việt vẫn chưa đúng.
Với mình tới đây coi như là đã đụng nóc rồi. Hy vọng mọi người sẽ bổ sung những điểm còn khuyết của thủ tục.
 
Upvote 0
Với mình tới đây coi như là đã đụng nóc rồi. Hy vọng mọi người sẽ bổ sung những điểm còn khuyết của thủ tục.
Chưa đụng nóc đâu bác ơi, đấy mới là cột chữ rồi đến cột số, nếu 2 cột chữ liền nhau thì ví dụ A1="a b", B1="c" sẽ cùng thứ tự với A2="a", B2="b c". Để khắc phục thì mỗi lần nối chuỗi vào biến temp ta thêm 2 ký tự space vào cuối.
 
Upvote 0
Chuyện chèn thêm dấu trống vào giữa là chuyện nhỏ.
Điểm quan trọng của phép ép kiểu số thành chuỗi là khi gặp số thực, có phần thập phân thì số sẽ rất khó chịu. Người viết code sẽ phải chọn lựa giới hạn bề rộng số, và vị trí dấu chấm (hiểu ngầm hay không hiểu ngầm). Thiên về bên trái thì có khả năng tràn số, thiên về bên phải thì mất độ chính xác.
Vì số trong windows có độ chính xác đến 15 chữ số cho nên dùng khoảng cố định rất khó. Cách dễ nhất là dùng vài ký tự để diễn tả 10^n
 
Upvote 0

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

Back
Top Bottom