Разделите коллекцию на n частей с помощью Lambda (или LINQ) в VB.Net - PullRequest
0 голосов
/ 01 мая 2018

Пример кода, представленного ниже, работает нормально, он делает то, что должен делать, но я не удовлетворен. Ищете гораздо более разумное решение в 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 голосов
/ 02 мая 2018

Мне кажется, что это самый простой способ сделать это:

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)
0 голосов
/ 02 мая 2018

Это второе самое быстрое, и я думаю, что вполне «чистое» решение, основанное на концепции @Enigmativity, опубликованной пару часов назад ... Заботится о его подходе n-band

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
0 голосов
/ 02 мая 2018

Вот как я бы попытался улучшить его:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...