问题
I have spent 2 days scouring the internet trying to find the solution to simply sort an array made up of a class of strings and integers (by just 1 of the string elements that may contain irregular characters). Please help! I have created a simplified code of what I am trying to do based on the microsoft example:
Public Class Form1
Class car
Public Make As String = ""
Public Year As Integer = 0
End Class
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim arrayOfCars() As car
Dim arrayElement As Integer = 0
'Exploded simplified loop to fill the array (original has 20 objects in the class
'and the array grows depending on input to no more than a few hundred.
ReDim arrayOfCars(0)
arrayOfCars(0) = New car
arrayOfCars(0).Make = "Ford"
arrayOfCars(0).Year = 1992
ReDim Preserve arrayOfCars(1)
arrayOfCars(1) = New car
arrayOfCars(1).Make = "Fiat"
arrayOfCars(1).Year = 1988
ReDim Preserve arrayOfCars(2)
arrayOfCars(2) = New car
arrayOfCars(2).Make = "Buick"
arrayOfCars(2).Year = 1932
ReDim Preserve arrayOfCars(3)
arrayOfCars(3) = New car
arrayOfCars(3).Make = "Ford"
arrayOfCars(3).Year = 1932
ReDim Preserve arrayOfCars(4)
arrayOfCars(4) = New car
arrayOfCars(4).Make = "Dodge"
arrayOfCars(4).Year = 1999
ReDim Preserve arrayOfCars(5)
arrayOfCars(5) = New car
arrayOfCars(5).Make = "Honda"
arrayOfCars(5).Year = 1977
'view array before sort
For i = 0 To 5
Debug.WriteLine(arrayOfCars(i).Make & vbTab & arrayOfCars(i).Year)
Next
Debug.WriteLine("*************************")
'sort array by the string component [Make]
'Array.Sort(arrayOfCars)
'arrayOfCars = arrayOfCars.OrderBy(Function(car) car.Make)
'????????????????
'view array after sort
For i = 0 To 5
Debug.WriteLine(arrayOfCars(i).Make & vbTab & arrayOfCars(i).Year)
Next
End Sub
End Class
回答1:
If you want to sort by the Make
property one out-of-the-box approach is using Array.Sort with the Comparison(Of T)
overload:
Array.Sort(arrayOfCars, Function(car1 As Car, car2 as Car)
Return car1.Make.CompareTo(car2.Make)
End Function)
Note that you should take care of cars which are Nothing
or (more likely) Make
-values which are Nothing
. Both would cause a NullReferenceException
. Therefore you could use:
Array.Sort(arrayOfCars, Function(car1 As Car, car2 As Car)
If Object.ReferenceEquals(car1,car2)
return 0
Else if car1 is nothing
Return -1
Else if car2 is nothing
Return 1
Else
return String.Compare(car1.Make, car2.Make)
End If
End Function)
Another (little less efficient since it needs to recreate the array) approach is LINQ:
Dim orderedCars = from car in arrayOfCars
order by car.Make Ascending
arrayOfCars = arrayOfCars.ToArray()
The LINQ approach is more maintainable and easier to read but it needs to create a new array. So if you don't want to modify the original array you should use that.
In general you should not use arrays if you want to add objects since arrays are fixed-sized collections. Use a List(Of Car)
instead, it has an Add method.
Another nitpick, follow .NET naming/capitalization conventions, use Car
instead of car
.
回答2:
Linq is your friend here and the OrderBy
method. But in order to use that your array needs to be a List
.
You can convert it to a List easily and sort it by the make like this (Not that this does not sort the original list, it creates a new list sorted by the criteria you specify):
Dim sortedListOfCars = arrayOfCars.ToList.OrderBy(Function(x) x.Make)
But it would be easier to declare it as a list to start with:
Dim listOfCars As New List(Of Car)
Then add your cars like this
listOfCars.Add(New Car With {.Make = "Ford", .Year = 1992})
listOfCars.Add(New Car With {.Make = "Fiat", .Year = 1988})
'etc.
Then you just OrderBy directly:
Dim sortedListOfCars = arrayOfCars.OrderBy(Function(x) x.Make)
回答3:
You could implement an IComparer for the Array.Sort() function.
Public Class CarComparer : Implements IComparer
Function Compare(x As car, y As car) As Integer _
Implements IComparer.Compare
Return New CaseInsensitiveComparer().Compare(x.Make, y.Make)
End Function
End Class
Use it like this:
Array.Sort(arrayOfCars, new CarComparer())
回答4:
If you're going to have this requirement frequently, you should implement a KeyComparer
class. This would allow you to come up with concise syntax, such as:
Array.Sort(arrayOfCars, New KeyComparer(Function(c As car) c.Make))
The Array.Sort(..., Comparison) approach suffers from the disadvantage that it doesn't handle nulls, and would throw NullReferenceException
if any of your list elements happen to be null. This may or may not be relevant to your case.
There are plenty of KeyComparer
implementations online. I've discussed this specific issue at length – and presented a sample C# implementation – in my KeyComparer article. The VB.NET conversion is below:
Public Class KeyComparer(Of TSource, TKey)
Inherits Comparer(Of TSource)
Private ReadOnly _keySelector As Func(Of TSource, TKey)
Private ReadOnly _innerComparer As IComparer(Of TKey)
Public Sub New(keySelector As Func(Of TSource, TKey), Optional innerComparer As IComparer(Of TKey) = Nothing)
_keySelector = keySelector
_innerComparer = If(innerComparer, Comparer(Of TKey).[Default])
End Sub
Public Overrides Function Compare(x As TSource, y As TSource) As Integer
If Object.ReferenceEquals(x, y) Then
Return 0
End If
If x Is Nothing Then
Return -1
End If
If y Is Nothing Then
Return 1
End If
Dim xKey As TKey = _keySelector(x)
Dim yKey As TKey = _keySelector(y)
Return _innerComparer.Compare(xKey, yKey)
End Function
End Class
来源:https://stackoverflow.com/questions/36470183/to-sort-a-class-array-in-vb-net