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

Ele*_*ios 5 .net linq vb.net ienumerable

题

在VB.Net中,如果我有这样的集合:

Dim collection As IEnumerable(Of Integer) = Enumerable.Range(0, 99)
Run Code Online (Sandbox Code Playgroud)

我怎么能把它分成不确定数量的元素的组/ Ienumebles?


条件

使用LINQ查询(不是MORELinq或任何其他第三方库)

不写入Function,只是使用(或附加到集合)LINQ查询,避免插入自定义和通用过程来分割部分.

不生成Anonymous类型(因为我会尊重VB.Net Option语句).


研究

我已经阅读过这些问题,但我无法正确地将C#LINQ查询转换为VB.Net(甚至在线翻译失败并需要进行大量修改):

使用LINQ将集合拆分为`n`部分?

如何将IEnumerable <String>拆分为IEnumerable <string>组

使用LINQ将列表拆分为子列表

将实体集合拆分为n个部分

这些是我尝试从上述SO问题中给出的解决方案中适应的两种不同方法,但是我的翻译不起作用,第一种不能编译,因为Group By和第二种条件不会产生分裂集合,它为每个元素生成一个集合:

1.

    Dim parts As Integer = 4
    Dim i As Integer = 0

    Dim splits As IEnumerable(Of IEnumerable(Of Integer)) =
        From item As Integer In collection
        Group By (Math.Max(Interlocked.Increment(i), i - 1) Mod parts)
        Into Group
        Select Group.AsEnumerable
Run Code Online (Sandbox Code Playgroud)

2.

    Dim parts As Integer = 4

    Dim result As IEnumerable(Of IEnumerable(Of Integer)) =
        collection.Select(Function(s, i) New With
            {
                Key .Value = s,
                Key .Index = i
            }
        ).GroupBy(Function(item)
                      Return (item.Index >= (item.Index / parts)) And (item.Index >= item.Value)
                  End Function,
               Function(item) item.Value).Cast(Of IEnumerable(Of Integer))()
Run Code Online (Sandbox Code Playgroud)

预期成绩

所以,如果我有这样的源集合:

Dim collection As IEnumerable(Of Integer) = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
Run Code Online (Sandbox Code Playgroud)

并假设我有那个想象的LINQ查询,它可以拆分成一个splits由变量指定的值命名的变量parts:

Dim parts as Integer = ...
Dim splits As IEnumerable(Of IEnumerable(Of Integer)) =
   From value As Integer In collection (Linq Query that splits by given 'parts' value)
Run Code Online (Sandbox Code Playgroud)

如果我选择该parts值为4,那么结果将是一个Enumerable(Of IEnumerable(Of Integer))包含3个集合的I ,其中:

splits(0) = {1, 2, 3, 4}
splits(1) = {5, 6, 7, 8}
splits(2) = {9, 10}
Run Code Online (Sandbox Code Playgroud)

如果我选择该parts值为5,那么结果将是一个Enumerable(Of IEnumerable(Of Integer))包含2个集合的I ,其中:

splits(0) = {1, 2, 3, 4, 5}
splits(1) = {6, 7, 8, 9, 10}
Run Code Online (Sandbox Code Playgroud)

如果我选择该parts值为1,则结果将是Enumerable(Of IEnumerable(Of Integer))包含相同源集合的I,因为我选择仅拆分1个部分:

splits(0) = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
Run Code Online (Sandbox Code Playgroud)

如果我选择该parts值为10,则结果将是Enumerable(Of IEnumerable(Of Integer))包含10个集合的I ,每个源示例集合的值为一个集合:

splits(0) = {1}
splits(1) = {2}
splits(2) = {3}
and so on...
Run Code Online (Sandbox Code Playgroud)

Bjø*_*sjå 4

您可以使用Range、Skip和Take来实现您的目标。

Dim collection As IEnumerable(Of Integer) = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
Dim parts As Integer = 4
Dim count As Integer = CInt(Math.Ceiling(collection.Count() / parts)) '= 3
Dim result As IEnumerable(Of IEnumerable(Of Integer)) = Nothing
Run Code Online (Sandbox Code Playgroud)

'Method 1:
result = From i In Enumerable.Range(0, count) Select collection.Skip(i * parts).Take(parts)
Run Code Online (Sandbox Code Playgroud)

'Method 2:
result = Enumerable.Range(0, count).Select(Function(i) collection.Skip(i * parts).Take(parts))
Run Code Online (Sandbox Code Playgroud)

For Each item In result
    Debug.WriteLine(String.Join(", ", item))
Next
Run Code Online (Sandbox Code Playgroud)

1, 2, 3, 4
5, 6, 7, 8
9, 10

强制延期方法:

Public Module Extensions

    <System.Runtime.CompilerServices.Extension()>
    Public Function Split(Of TSource)(collection As IEnumerable(Of TSource), ByVal parts As Integer) As IEnumerable(Of IEnumerable(Of TSource))
        If (collection Is Nothing) Then Throw New ArgumentNullException("collection")
        If (parts < 1) Then Throw New ArgumentOutOfRangeException("parts")
        Dim count As Integer = collection.Count()
        If (count = 0) Then Return {}
        If (parts >= count) Then Return {collection}
        Return Enumerable.Range(0, CInt(Math.Ceiling(count / parts))).Select(Function(i) collection.Skip(i * parts).Take(parts))
    End Function

End Module
Run Code Online (Sandbox Code Playgroud)

result = collection.Split(4)
Run Code Online (Sandbox Code Playgroud)