使用IComparable对缺失和重复的序号进行排序

时间:2017-02-17 16:55:32

标签: .net vb.net sorting icomparable

我的任务是编写代码以使用IComparable和我们的自定义类型(Product)。

Product类型具有名为OrdinalNumber的属性,该属性是排序操作的比较属性。序数的一个例子可以是这样的:1 2 3 3 5 6 7 7 9等。例程必须替换重复或缺失的序数并对结果进行排序。

我找到了这个例子,让它运转起来。 https://msdn.microsoft.com/en-us/library/w56d4y5z(v=vs.110).aspx

有人可以帮帮我吗?

我不想对DataTable进行排序。我们目前有代码对DataTable进行排序,我们希望重写该代码以使用名为Product的自定义类型。我粘贴的示例代码使用新的Product类。

这是我到目前为止所做的:

Imports System.Collections.Generic

Public Class Product
    Implements IEquatable(Of Product)
    Implements IComparable(Of Product)
    Public Property ProductName() As String
        Get
            Return m_ProductName
        End Get
        Set(value As String)
            m_ProductName = value
        End Set
    End Property
    Private m_ProductName As String

    Public Property ProductId() As Integer
        Get
            Return m_ProductId
        End Get
        Set(value As Integer)
            m_ProductId = value
        End Set
    End Property
    Private m_ProductId As Integer

    Public Property OrdinalNumber() As Integer
        Get
            Return m_OrdinalNumber
        End Get
        Set(value As Integer)
            m_OrdinalNumber = value
        End Set
    End Property
    Private m_OrdinalNumber As Integer

    Public Overrides Function ToString() As String
        Return "Ordinal Number: " & OrdinalNumber & "   ID: " & ProductId & "   Name: " & ProductName
    End Function

    Public Overrides Function Equals(obj As Object) As Boolean
        If obj Is Nothing Then
            Return False
        End If
        Dim objAsProduct As Product = TryCast(obj, Product)
        If objAsProduct Is Nothing Then
            Return False
        Else
            Return Equals(objAsProduct)
        End If
    End Function

    Public Function SortByNameAscending(name1 As String, name2 As String) As Integer

        Return name1.CompareTo(name2)
    End Function

    Public Function CompareTo(compareProduct As Product) As Integer _
            Implements IComparable(Of Product).CompareTo

        If compareProduct Is Nothing Then
            Return 1
        Else

            Return Me.OrdinalNumber.CompareTo(compareProduct.OrdinalNumber)
        End If
    End Function

    Public Overrides Function GetHashCode() As Integer
        Return OrdinalNumber
    End Function

    Public Overloads Function Equals(other As Product) As Boolean Implements IEquatable(Of Product).Equals
        If other Is Nothing Then
            Return False
        End If
        Return (Me.OrdinalNumber.Equals(other.OrdinalNumber))
    End Function

End Class

1 个答案:

答案 0 :(得分:2)

我不确定为什么会对SelectionSort的Bingo变体(现在通过编辑进行编辑)有这样的关注。当有许多重复值时,宾果游戏版本的SelectionSort版本稍微快一点,但只是略有不同。它不是一种专门针对存在欺骗行为的情况的分拣机。它们都很慢。

How would I implement a selection or "bingo" sort using List.Sort
那不是它的工作原理。实际的排序机制内置于.NET Framework中。在List.Sort()的情况下,它将根据需要选择3种中的一种。您可以提供比较机制。

给定{1,3,5,5,7,9,15}的数据集13的元素总是低于51024,因此缺少的元素不是问题。您希望如何比较重复值。

有几种选择:

Linq的订单

Dim sortedProds = myProducts.OrderBy(Function (j) j.Ordinal).ToList()

时间: ~6 ms 适用于20k项目
如果你想对dupes做一些事情,比如用Id:

排序他们
Dim ProdsL = myProducts.OrderBy(Function(j) j.Ordinal).
                   ThenBy(Function(k) k.Id).ToList()

时间: ~8 ms 适用于20k物品

List.Sort使用比较器

使类实现IComparable

Public Function CompareTo(other As ProductItem) As Integer _ 
                         Implements IComparable(Of ProductItem).CompareTo
    If Ordinal < other.Ordinal Then Return -1
    If Ordinal > other.Ordinal Then Return 1

    ' equal, return the lower ID or:
    'Return 0

    If Id < other.Id Then Return -1
    Return 1
End Function

用法:

myProducts.Sort(Function(x, y) x.CompareTo(y))

时间: ~28 ms ,适用于20k物品

您还可以使用执行比较的方法,这意味着您不必实施IComparable,除非它在其他情况下具有价值。

Private Function ProductComparer(x As ProductItem, y As ProductItem) As Integer
    If x.Ordinal < y.Ordinal Then Return -1
    If x.Ordinal > y.Ordinal Then Return 1

    ' equal, return the lower ID or:
    'Return 0

    If x.Id < y.Id Then Return -1
    Return 1
End Function

用法:

myProducts.Sort(AddressOf ProductComparer)

时间: 11 ms

宾果排序

SelectionSort(~3650 ms)和Bingo变化(~3590 ms)远远落后于其他变量,它们似乎不值得考虑。包含Bingo只是为了满足原始问题(即使其他地方已经有一个问题)。

  Private Sub BingoSort(items As List(Of ProductItem))
    ' converted from https://en.wikipedia.org/wiki/Selection_sort#Variants
    ' for http://stackoverflow.com/q/42303395/1070452

    Dim max As Int32 = items.Count - 1
    Dim nextVal = items(max).Ordinal
    Dim value As Int32
    Dim tmp As ProductItem

    For i As Int32 = max - 1 To 0 Step -1
        If items(i).Ordinal > nextVal Then
            nextVal = items(i).Ordinal
        End If
    Next
    While (max > 0) And (items(max).Ordinal = nextVal)
        max -= 1
    End While
    While (max > 0)
        value = nextVal
        nextVal = items(max).Ordinal
        For i As Int32 = max - 1 To 0 Step -1
            If items(i).Ordinal = value Then
                tmp = items(i)
                items(i) = items(max)
                items(max) = tmp
                max -= 1
            ElseIf items(i).Ordinal > nextVal Then
                nextVal = items(i).Ordinal
            End If
        Next
        While (max > 0) And (items(max).Ordinal = nextVal)
            max -= 1
        End While
    End While
End Sub

用法:

BingoSort(myProducts)

时间: ~3590 ms ,适用于20k物品。

请注意,如果没有欺骗(或原始列表以Id顺序开头),则结果与linq&#39; s OrderBy

相同
Dim Valid = ProdsLinq.SequenceEqual(ProdsBingo)

鉴于表现不佳,似乎没有理由在这里使用它。 IComparable可让您决定如何打破重复项,Linq和List.Sort(IComparable)的速度更快。但

请注意,DataTable

存在类似的内容
myDT.DefaultView.Sort = "Ordinal ASC"
' or
myDT.DefaultView.Sort = "Ordinal ASC, Id ASC"