使用Lambda(或LINQ)在VB.Net中将集合拆分为n个部分

时间:2018-05-01 20:20:52

标签: vb.net linq lambda

下面提供的代码示例工作正常,它正在做应该做的事情,但我并不满意。在VB.NET中寻找更智能的解决方案。结果的呈现(我的意思是每个小组的计数)非常尴尬。数据内容和记录列表等并不重要。此外,计数应按顺序排列{0},从{1}到{2},更多,然后是{3} ...先谢谢。

    Dim Age1 As Integer = 5
    Dim Age2 As Integer = 9
    Dim myList As New List(Of Integer) = {1, 3, 5, 7, 9, 2, 4, 6, 8, 10, 2, 4, 5, 7, 8, 9, 6, 7, 9, 11}
    Dim Lambda = myList.GroupBy(Function(x) New With {Key .Age1 = (x) < Age1,Key .Age2 = (x) > Age1 - 1 And (x) <= Age2,Key .Age3 = (x) > Age2}).ToList()
    Dim group1, group2, group3 As Integer
    myList = myList.OrderBy(Function(x) x).ToList()
    Console.WriteLine(String.Join(",", myList.Select(Function(s) s.ToString).ToArray))
    For Each group In Lambda
        If group.Key.Age1 Then group1 = group.Count()
        If group.Key.Age2 Then group2 = group.Count()
        If group.Key.Age3 Then group3 = group.Count()
    Next
    ' Obviously If Stop Then Error condition
    If group1 + group2 + group3 <> myList.Count Then Stop

    Console.WriteLine(String.Format("Groups: Less{0},From{1}To{2},MoreThan{3}", Age1, Age1, Age2 - 1, Age2))
    Console.WriteLine(String.Format("   Age:  {0,4},{1,8},{2,8}", group1, group2, group3))
    '1,2,2,3,4,4,5,5,6,6,7,7,7,8,8,9,9,9,10,11
    'Groups: Less5,From5To8,MoreThan9
    'Age:     6,      12,        2

3 个答案:

答案 0 :(得分:1)

以下是我将如何改进它:

Dim Age1 As Integer = 5
Dim Age2 As Integer = 9

Dim myList As New List(Of Integer) From {1, 3, 5, 7, 9, 2, 4, 6, 8, 10, 2, 4, 5, 7, 8, 9, 6, 7, 9, 11}
Console.WriteLine(String.Join(", ", myList.OrderBy(Function(x) x)))
console.WriteLine

Dim ageBins = myList.GroupBy(Function(age) If(age < Age1, 1, If(age >= Age1 And age <= Age2, 2, 3))) _
                    .Select(Function(agebin) New With { agebin.Key, .AgeCount = agebin.Count() }) _
                    .OrderBy(Function(agebin) agebin.Key)

For Each bin In ageBins
    Dim msg As String
    Select bin.Key
        Case 1
            msg = $"Less {Age1}"
        Case 2
            msg = $"From {Age1} To {Age2}"
        Case Else
            msg = $"MoreThan {Age2}"
    End Select
    Console.WriteLine($"{msg,12}: {bin.AgeCount}")
Next

您还可以更改代码以处理任意数量的分档:

Dim agesForBins = {5, 10}
Dim ageBins = myList.GroupBy(Function(age) Enumerable.Range(0, agesForBins.Length).Where(Function(n) age < agesForBins(n)).DefaultIfEmpty(agesForBins.Length).First) _
                    .Select(Function(agebin) New With { agebin.Key, .AgeCount = agebin.Count() }) _
                    .OrderBy(Function(agebin) agebin.Key)

For Each bin In ageBins
    Dim msg As String
    If bin.Key = 0 Then
        msg = $"Less {agesForBins(0)}"
    ElseIf bin.Key = agesForBins.Length Then
        msg = $"MoreThan {agesForBins(bin.Key-1)-1}"
    Else
        msg = $"From {agesForBins(bin.Key-1)} To {agesForBins(bin.Key)-1}"
    End If

    Console.WriteLine($"{msg,12}: {bin.AgeCount}")
Next

答案 1 :(得分:1)

在我看来,这是最简单的方法:

Dim Age1 As Integer = 5
Dim Age2 As Integer = 9
Dim myList As New List(Of Integer) From {1, 3, 5, 7, 9, 2, 4, 6, 8, 10, 2, 4, 5, 7, 8, 9, 6, 7, 9, 11}

Dim group1 As Integer = myList.Where(Function (x) x < Age1).Count()
Dim group2 As Integer = myList.Where(Function (x) x > Age1 - 1 And x <= Age2).Count()
Dim group3 As Integer = myList.Where(Function (x) x > Age2).Count()

If group1 + group2 + group3 <> myList.Count Then Stop

Console.WriteLine(String.Format("Groups: Less{0},From{1}To{2},MoreThan{3}", Age1, Age1, Age2 - 1, Age2))
Console.WriteLine(String.Format("   Age:  {0,4},{1,8},{2,8}", group1, group2, group3))

如果你想要一个基于LINQ的时髦方法,那么试试这个:

Dim bands() As Func(Of Integer, Boolean) = _
{ _
    Function (x) x < Age1, _
    Function (x) x <= Age2, _
    Function (x) True _
}

Dim counts = _
    myList _
        .GroupBy(Function (x) Enumerable.Range(0, bands.Count).Where(Function (n) bands(n)(x)).First()) _
        .Select(Function (x) x.Count()) _
        .ToArray()

Dim group1 As Integer = counts(0)
Dim group2 As Integer = counts(1)
Dim group3 As Integer = counts(2)

答案 2 :(得分:0)

这是最快的2,我觉得很干净&#39;几个小时前发布的基于@Enigmativity概念的解决方案...关注他的n波段方法

Function simpleCSVsplit(ageForBins() As Integer, myList As List(Of Integer)) As List(Of Integer)
    Dim Bands As New List(Of Integer)
    For indx As Integer = 0 To ageForBins.Count - 1
        Bands.Add(myList.Where(Function(x) x < ageForBins(indx)).Count())
        myList = myList.Skip(Bands(indx)).ToList()
    Next
    Bands.Add(myList.Count)
    Return Bands
End Function