基于作为字符串数组的对象的属性,使用Linq对对象列表进行排序

时间:2016-02-23 20:32:52

标签: vb.net linq

我有一个List(MatrixComponent),我正在尝试排序。

Public Class MatrixComponent
    Public Property Id As Integer
    Public Property Matrix As Integer 
    Public Property Output As String
    Public Property Sorts As String()
End Class

我需要对列表进行排序:

  1. 由Output属性(文件路径,字符串)
  2. 对象的Sorts属性
  3. 中的每个数组值

    Sorts数组中的元素数量可能因对象而异,但如果数组有3个元素,则它将包含3个字符串值,其中任何一个都可以是空字符串。

    示例:

    请记住,我的示例数据使用存储为字符串的数字,因为我发现它们更容易查看,但是,数组中的值是字符串,应该按字符串排序。你基本上可以有一个包含以下{“10”,“abc”,“1abc5d”}的数组

    Dim m As New List(Of MatrixComponent)
    m.Add(New MatrixComponent() With {.Id = 1, .Output = "c:\a.pdf", .Sorts = {"10", "30"}})
    m.Add(New MatrixComponent() With {.Id = 2, .Output = "c:\a.pdf", .Sorts = {"10"}})
    m.Add(New MatrixComponent() With {.Id = 3, .Output = "c:\a.pdf", .Sorts = {"10", "20"}})
    m.Add(New MatrixComponent() With {.Id = 4, .Output = "c:\a.pdf", .Sorts = {}})
    m.Add(New MatrixComponent() With {.Id = 5, .Output = "c:\a.pdf", .Sorts = {"9", "1"}})
    m.Add(New MatrixComponent() With {.Id = 6, .Output = "c:\a.pdf", .Sorts = {"10"}})
    

    我期待以下顺序:

    4, 2, 6, 3, 1, 5
    
    Id             Col1       col2     col3
    =======================================
    4              NULL       NULL     NULL
    2              10         NULL     NULL
    6              10         NULL     NULL
    3              10         20       NULL
    1              10         30       NULL
    5              9          1        NULL
    
    
    id=4, sort=""
    id=2, sort="10"
    id=6, sort="10"
    id=3, sort="10", "20"
    id=1, sort="10", "30"
    id=5, sort="9", "1"
    

    我能够通过以下Linq查询获得正确的顺序:

    Dim sorted As IOrderedEnumerable(Of MatrixComponent) =
    items.OrderBy(Function(u) u.Output) _
    .ThenBy(Function(y) If(y.Sorts Is Nothing, "", y.Sorts(0))) _
    .ThenBy(Function(y) If(y.Sorts Is Nothing OrElse y.Sorts.Length <= 1, "", y.Sorts(1))) _
    .ThenBy(Function(y) If(y.Sorts Is Nothing OrElse y.Sorts.Length <= 2, "", y.Sorts(2)))
    

4 个答案:

答案 0 :(得分:2)

我只是连接Sorts数组中的字符串,然后按该组合字符串排序。

答案 1 :(得分:1)

有很多我们都不知道。这假定:

  • 底部的块表示&#34;字符串&#34;数组(即使表示整数)。
  • 您希望丢失的元素排序高于其余元素
  • 不清楚是否还有空字符串
Dim sorts As String() = {"10", "35", "20", "50", "40"}

Dim matList As New List(Of MatrixComponent)

matList.Add(New MatrixComponent With {.Id = 1, .Matrix = 1})
matList.Add(New MatrixComponent With {.Id = 99, .Matrix = 9})
matList.Add(New MatrixComponent With {.Id = 78, .Matrix = 7})
matList.Add(New MatrixComponent With {.Id = 4, .Matrix = 6})
matList.Add(New MatrixComponent With {.Id = 43, .Matrix = 3})
matList.Add(New MatrixComponent With {.Id = 123, .Matrix = 12})

' add randomized sort data
For Each m In matList
    ' sets a random number 0-3 values
    m.Sorts = sorts.OrderBy(Function(r) RNG.Next()).Take(RNG.Next(0, 3)).ToArray
Next
' force a "" into one of them:
matList(2).Sorts = {"", "10", "35", "60", "20"}

Dim sortedlist = matList.OrderBy(Function(x) GetSortValue(x.Sorts, 0)).
                    ThenBy(Function(y) GetSortValue(y.Sorts, 1)).
                    ThenBy(Function(z) GetSortValue(z.Sorts, 2)).ToList()

然后是帮手:

Private Function GetSortValue(strArry As String(), ndx As Int32) As Int32
    Dim intVal As Int32 = Int32.MaxValue

    If ndx < strArry.Length Then
        If Int32.TryParse(strArry(ndx), intVal) Then
            Return intVal
        Else
            Return Int32.MaxValue
        End If
    End If
    Return intVal
End Function

帮助程序将字符串(如果存在)解析为整数,并在不存在时返回高默认值。从技术上讲,它不完全是一条线linq链。帮助者可以用1-2 x = If()运算符替换,但我不确定在那里粘贴3次会更清楚。

测试:

For Each m In sortedlist
    Console.WriteLine("{0:000}  {1}", m.Id, String.Join(", ", m.Sorts))
Next

输出:

078  20, 10, 35, 60, 
004  20, 10
099  35, 20
123  40
001  
043

(第一个数字是Id)

我喜欢使用字符串数组的concat进行简单排序的想法。这有一些限制:没有单个数字(也许没有9 s)。例如,给出以下数据:

Dim sorts As String()() = {New String() {"10", "90", "20", "35", "40"},
                           New String() {"10", "9", "2", "35", "40"},
                           New String() {"1", "90", "9", "35", "40"},
                           New String() {"19", "90", "20", "35", "40"},
                           New String() {"20", "9", "20", "35", "40"},
                           New String() {"2", "90", "20", "35", "40"}
                           }

结果非常错误:

001  1090203540
099  10923540
078  19093540
004  1990203540
043  209203540
123  290203540

为第78号分配了{"1", "90", "9", "35", "40"}因此它应该排在第一个元素的顶部。 "19093540"中从第二组转移的前九个影响整体排序。按数值排序:

078  1,90,9,35,40
123  2,90,20,35,40
099  10,9,2,35,40
001  10,90,20,35,40
004  19,90,20,35,40
043  20,9,20,35,40

123元素更有趣。 "2"应该排在第二位。 "290"不一样,并将其放在最底层。

String.Join / Concat可以正常工作,但依赖于数据的性质。如果字符串数组是数字,并且您希望按数值排序,则必须将它们转换为数字。数字和数字排序不同。

答案 2 :(得分:0)

最后,我的解决方案始终如一。问题是这一行:

Dim maxSorts As Integer = sorted.Max(Function(x) If(x.Sorts Is Nothing, 0, x.Sorts.Length))
For i = 0 To maxSorts

我应该早点抓住这个,但是它滑倒了我。获取要迭代的Max数​​组长度是从1开始的,但是数组元素从0开始。我实际上对列表进行了多次排序,这是重置排序顺序。愚蠢的问题。

答案 3 :(得分:-1)

这对你有用吗?

Dim sorted = _
    matrixComponents _
        .OrderBy(Function (m) String.Join("|", If(m.Sorts, { }))) _
        .ToList()