【问题标题】:Sort List(of Object) by object properties按对象属性排序列表(对象)
【发布时间】:2016-08-17 09:40:57
【问题描述】:

我正在努力实现已经给出答案的目标。但它在c#,我对c#一无所知,所以我正在寻找一个vb.net替代品。

我创建了一个名为BomItemclass,它具有数量、描述等多个属性。

我将这些 BomItems 添加到 List(of BomItem) 中,但现在我想根据属性对它们进行排序。如何根据ItemNumber 属性对项目进行排序?

这是我找到的c# 解决方案的link

我的班级代码

Public Class BomItem
    Public Property ItemNumber As String
    Public Property Description As String
    Public Property Quantity As Double
    Public Property Material As String
    Public Property Certificate As String
End Class

我如何添加 BomRow 对象

    _NewBomList.Add(New BomItem() With {
                    .ItemNumber = oRow.ItemNumber,
                    .Description = oPropSet.Item("Description").Value,
                    .Quantity = oRow.TotalQuantity,
                    .Material = oPropSet.Item("Material").Value,
                    .Certificate = CustomPropertySet.Item("Cert.").Value})

比较器

Public Class NaturalSort

Implements IComparer

Public Function Compare(ByVal x As Object,
            ByVal y As Object) As Integer Implements IComparer.Compare

    ' [1] Validate the arguments.
    Dim s1 As String = x
    If s1 = Nothing Then
        Return 0
    End If

    Dim s2 As String = y
    If s2 = Nothing Then
        Return 0
    End If

    Dim len1 As Integer = s1.Length
    Dim len2 As Integer = s2.Length
    Dim marker1 As Integer = 0
    Dim marker2 As Integer = 0

    ' [2] Loop over both Strings.
    While marker1 < len1 And marker2 < len2

        ' [3] Get Chars.
        Dim ch1 As Char = s1(marker1)
        Dim ch2 As Char = s2(marker2)

        Dim space1(len1) As Char
        Dim loc1 As Integer = 0
        Dim space2(len2) As Char
        Dim loc2 As Integer = 0

        ' [4] Collect digits for String one.
        Do
            space1(loc1) = ch1
            loc1 += 1
            marker1 += 1

            If marker1 < len1 Then
                ch1 = s1(marker1)
            Else
                Exit Do
            End If
        Loop While Char.IsDigit(ch1) = Char.IsDigit(space1(0))

        ' [5] Collect digits for String two.
        Do
            space2(loc2) = ch2
            loc2 += 1
            marker2 += 1

            If marker2 < len2 Then
                ch2 = s2(marker2)
            Else
                Exit Do
            End If
        Loop While Char.IsDigit(ch2) = Char.IsDigit(space2(0))

        ' [6] Convert to Strings.
        Dim str1 = New String(space1)
        Dim str2 = New String(space2)

        ' [7] Parse Strings into Integers.
        Dim result As Integer
        If Char.IsDigit(space1(0)) And Char.IsDigit(space2(0)) Then
            Dim thisNumericChunk = Integer.Parse(str1)
            Dim thatNumericChunk = Integer.Parse(str2)
            result = thisNumericChunk.CompareTo(thatNumericChunk)
        Else
            result = str1.CompareTo(str2)
        End If

        ' [8] Return result if not equal.
        If Not result = 0 Then
            Return result
        End If
    End While

    ' [9] Compare lengths.
    Return len1 - len2

End Function

End Class

【问题讨论】:

标签: vb.net list sorting properties


【解决方案1】:

使用LINQOrderBy

_NewBomList.OrderBy(Function(bi) bi.ItemNumber)

对于降序:

_NewBomList.OrderByDescending(Function(bi) bi.ItemNumber)

如果你想在你的字符串中使用数字顺序,你必须先将它转换为整数:

_NewBomList.OrderBy(Function(bi) Integer.Parse(bi.ItemNumber))

编辑:
要为 OrderBy 扩展提供自定义 IComparer,您必须创建一个实现 IComparer(Of String) 的类,其中 String 是要比较的 ItemNumbers

 Class ItemNumberComparer  
     Implements IComparer(Of String)

     Public Function Compare(String x, String y)
         Dim ix As String() = x.Split("."C)
         Dim iy As String() = y.Split("."C)

         Dim maxLen As Integer = Math.Max(ix.Length, iy.Length)
         For i As Integer = 0 To maxLen - 2
             If ix.Length >= i AndAlso iy.Length >= i Then
                If Integer.Parse(ix(i)) < Integer.Parse(iy(i)) Then
                   Return -1 'If x.i is LT y.i it must be smaller at all
                ElseIf Integer.Parse(ix(i)) > Integer.Parse(iy(i)) Then
                   Return 1 'If x.i is GT y.i it must be bigger all
                End If
             End If
         Next
         'This code is only executed if x and y differ at last number or have different ´number of dots
        If ix.Length = iy.Length Then
            Return Integer.Parse(ix(ix.Length - 1)).CompareTo(Integer.Parse(iy(iy.Length - 1))) 'Only last number differs
       Else
           Return ix.Length.CompareTo(iy.Length) 'The number with more dots is smaller
       End If

     End Function     
  End Class

调用语法:

Dim comparer = new ItemNumberComparer()
_NewBomList.OrderByDescending(Function(bi) bi.ItemNumber, comparer)

【讨论】:

  • 将执行自然排序还是按 ascii 模型? 1,2,3,4,5,6,7,8,9,10 或 1,10,2,20,3,30 ... ?
  • 如果您不提供任何自定义 IComparer,它将按字母顺序排序 (1,10,2,20,...)
  • 如果您希望项目按文本值按数字排序,则必须将 String 值转换为数字,例如_NewBomList.OrderBy(Function(bi) CInt(bi.ItemNumber))。问题是,如果您的值表示数字,那么为什么要将它们存储在 String 属性中?
  • 我的最后一条评论不是 100% 正确:您可以将字符串转换为数字(例如整数)以在不使用自定义 IComparer 的情况下达到相同的结果。
  • Ok fair comment ;) 我实现了一个替代的自然比较器,它的行数比你的例子少。也许它也对你有用。
【解决方案2】:

来自其他线程的 C# 代码:

List<Order> SortedList = objListOrder.OrderBy(o=>o.OrderDate).ToList();

相当于这个 VB 代码:

List(Of Order) SortedList = objListOrder.OrderBy(Function(o) o.OrderDate).ToList()

如您所见,变化很小。您只需要了解泛型和 lambda 表达式的语法即可。

不过,您应该知道,此代码不会对您的列表进行排序。它对列表中的项目进行排序,然后按该顺序将它们添加到新列表中。这对于许多应用程序来说非常好,但是如果您在其他地方使用相同的列表,那么您将不会在那里看到新订单。虽然有一些变化,但实际对列表进行排序的一种方法是这样的:

objListOrder.Sort(Function(o1, o2) o1.OrderDate.CompareTo(o2.OrderDate))

【讨论】:

    【解决方案3】:

    另一种解决方案是实现IComparable (see MSDN ref) 接口。此界面旨在以自定义方式对您的对象进行排序:

    Public Class BomItem
        Implements IComparable
    
        Public Property ItemNumber As String
        Public Property Description As String
        Public Property Quantity As Double
        Public Property Material As String
        Public Property Certificate As String
    
        Public Function CompareTo(obj As Object) As Integer
             Dim bom = CType(obj, BomItem)
    
             If Not bom Is Nothing then
                 Return Me.ItemNumber.CompareTo(bom.ItemNumber)
             Else
                 Throw New ArgumentException("Object is not a BomItem")
             End If
    End Class
    

    您可以这样对列表进行排序:

    Dim myList As New List(Of BomItem)
    
    'Code to add your BomItems
    
    myList.Sort()
    

    这实际上会对您的列表进行排序,它不会创建新列表。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-05-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-26
      相关资源
      最近更新 更多