2

I have a list of objects and I'm trying to sort by two properties with one property being sorted by a custom order. The list has properties of ReqType and PartNumber. ReqType will be "M", "B", "S", or null and I would like to sort the list in that order. Then sort by PartNumber.

Input list:
PartNumber    ReqType
124           B
125           M
123           B
121           S
120           M
115            

Expected Sort:
PartNumber    ReqType
120           M
125           M
123           B
124           B
121           S
115            

I started with the code below but that only sorts ReqType alphabetically.

Return EBom.OrderBy(Function(f) f.ReqType).ThenBy(Function(f) f.PartNumber).ToList 

I then found a method to create a custom sort order using the code below. Though using Ebom.Sort() doesn't seem to allow me to tack on the second sort order for PartNumber. I realize I could probably add the PartNumber sorting to the custom function but that seems like a lot of work.

EBom.Sort()
Return EBom.ToList


Implements IComparable(Of EBomList)
Public Function SortReq(other As EBomList) As Integer Implements IComparable(Of EBomList).CompareTo
    If (Me.ReqType = other.ReqType) Then
        Return 0
    ElseIf (Me.ReqType = "M") Then
        Return -1
    ElseIf (Me.ReqType = "B") Then
        If (other.ReqType = "M") Then
            Return 1
        Else
            Return -1
        End If
    ElseIf (Me.ReqType = "S") Then
        If (other.ReqType = "M" Or other.ReqType = "B") Then
            Return 1
        Else
            Return -1
        End If
    Else
        Return 1
    End If
End Function

Is there an easier way to sort by a custom order or at least combine the custom sort function with a .thenby(.....) to get the order I'd like?

3 Answers 3

3

Cleaner code version to do this is to use a Function in the sort method like the following.

    d.Sort(Function(X As EBomList, Y As EBomList)
               Dim Tx As Integer = InStr("MBS ", X.ReqType.PadLeft(1, " "c))
               Dim Ty As Integer = InStr("MBS ", Y.ReqType.PadLeft(1, " "c))
               Select Case Tx
                   Case Is < Ty : Return -1
                   Case Is > Ty : Return 1
                   Case Else : Return X.PartNumber.CompareTo(Y.PartNumber)
               End Select
           End Function)

Note it only needs to check the partnumber when the type code is the same.

I am assuming your Partnumber is in fact a number. If it is a string you will need to pad it as appropriate. For example.

Return X.PartNumber.PadLeft(6," "c).CompareTo(Y.PartNumber.PadLeft(6," "c))

ALTERNATIVE AND FASTER APPROACH

If you have A LOT of data you may want to consider augmenting the EBomLit to create a sort key rather than doing that string search though...

As in...

Private _ReqType As String
Private _TypeKey As Integer 

Public Property ReqType As String
    Get
        Return _ReqType
    End Get
    Set(value As String)
        _ReqType = value
        _TypeKey = InStr("MBS ", value.PadLeft(1, " "c))
    End Set
End Property

Public ReadOnly Property TypeKey As Integer
    Get
        Return _TypeKey
    End Get
End Property

Then the sort becomes...

    d.Sort(Function(X As EBomList, Y As EBomList)
               Select Case X.TypeKey
                   Case Is < Y.TypeKey : Return -1
                   Case Is > Y.TypeKey : Return 1
                   Case Else : Return X.PartNumber.CompareTo(Y.PartNumber)
               End Select
           End Function)

FASTER STILL

You could even extend that further by creating a full sort key out of the "TypeKey" with the padded "PartNumber" and use those as a key to save the whole shebang in a SortedDictionary instead of a List.

Sign up to request clarification or add additional context in comments.

Comments

2

Just create a list of ReqTypes and lookup the index:

Dim sortOrder = "MBS "

Dim sortedList = List.OrderBy(Function(x) sortOrder.IndexOf(If(x.ReqType Is Nothing, " ", x.ReqType))).ThenBy(Function(x) x.PartNumber).ToList()

Note: If sorting by something other than chars then you will need to create a propper array/list of the object to compare by.

Comments

0

A bit easier with Enum and Tuple if those are an option:

Enum PartNumber As Byte : M : B : S : __ : End Enum

Dim list = New List(Of Tuple(Of PartNumber, Integer)) From {
    Tuple.Create(PartNumber.B, 124),
    Tuple.Create(PartNumber.M, 125),
    Tuple.Create(PartNumber.B, 123),
    Tuple.Create(PartNumber.S, 121),
    Tuple.Create(PartNumber.M, 120),
    Tuple.Create(PartNumber.__, 115)}

list.Sort()

For Each item In list
    Debug.Print(item.Item2 & vbTab & item.Item1.ToString.Replace("_", ""))
Next

Output:

120 M
125 M
123 B
124 B
121 S
115 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.