Chuckv
Chuckv

Reputation: 31

LINQ Order BY using literal values in VB.NET?

I'm new to LINQ, would like to sort by a custom literal order... not sure of the syntax to do so (assuming it is possible). Thanks!

Class Foo
    Sub New(Name As String, Position As Integer)
        Me.Name = Name
        Me.Position = Position
    End Sub
    Public Name As String
    Public Position As Integer
End Class

Sub Main()
    Dim l As New List(Of Foo)
    l.Add(New Foo("Something1", 1))
    l.Add(New Foo("Something2", 2))
    l.Add(New Foo("Something3", 3))

Dim literalSort = ..... 'sort l by this literal order... "2, 3, 1"

Upvotes: 2

Views: 1854

Answers (4)

D Stanley
D Stanley

Reputation: 152566

Adapting this answer to VB:

Dim order = New Integer() {2,3,1}

Dim literalSort = l.OrderBy(Function(i) If(order.Contains(i), 0, 1)) _ 
                   .ThenBy(Function(i) Array.IndexOf(order, i)) _
                   .ThenBy(Function(i) i)  ' sort rest numerically

Upvotes: 1

Matt Wilko
Matt Wilko

Reputation: 27342

It sounds like what you need is a customer comparer that implements IComparer(Of Foo).

The example that follows sorts the items in the list according to the Value which is what I have assumed you are after. It should be easier enough to change this if it is not exactly as you want.

Public Class SpecificListComparer
    Implements IComparer(Of Foo)
    Private _order As Integer() = {2, 3, 1}
    Public Function Compare(x As Foo, y As Foo) As Integer Implements IComparer(Of Foo).Compare
        'TODO - check for null values
        If x.Value = y.Value AndAlso x.Name = y.Name Then Return 0
        If x.Value = y.Value Then Return x.Name.CompareTo(y.Name)
        Return Array.IndexOf(_order, x.Value).CompareTo(Array.IndexOf(_order, y.Value))
    End Function
End Class

Then you just use it like this:

l.Sort(New SpecificListComparer)

Upvotes: 0

Maurice Reeves
Maurice Reeves

Reputation: 1583

Given the seeming arbitrary nature of the ordering you want to achieve, I'd create a method with a case statement and then return the order you want, based on the position:

Public Function OrderFoo (ByVal foo as Foo) as Integer
    Select Case foo.Position
        Case 2 
            Return 1
        Case 3
            Return 2
        Case 1
            Return 3
        Case Else
            Return 100
    End Select
End Function

Call the method in the OrderBy in LINQ and make sure you document why you're choosing the ordering that you are.

You should be able to call the method like below:

From foo In l _
Select foo _
Order By OrderFoo(foo)

Upvotes: 1

Matt Wilko
Matt Wilko

Reputation: 27342

This will create a new list ordered as specified in the orderedNumbers array:

    Dim l As New List(Of Foo)
    l.Add(New Foo("Something1", 1))
    l.Add(New Foo("Something2", 2))
    l.Add(New Foo("Something3", 3))

    Dim orderedNumbers As Integer() = {2, 3, 1}
    Dim outputList As New List(Of Foo)
    For Each num In orderedNumbers
        outputList.Add(l.Item(num - 1))
    Next

Upvotes: 0

Related Questions