Ala*_*Maw 44 c# linq ienumerable
我想把IEnumerable<T>它分成固定大小的块.
我有这个,但由于所有列表创建/复制,它似乎不优雅:
private static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> items, int partitionSize)
{
List<T> partition = new List<T>(partitionSize);
foreach (T item in items)
{
partition.Add(item);
if (partition.Count == partitionSize)
{
yield return partition;
partition = new List<T>(partitionSize);
}
}
// Cope with items.Count % partitionSize != 0
if (partition.Count > 0) yield return partition;
}
Run Code Online (Sandbox Code Playgroud)
有没有更惯用的东西?
编辑:虽然这已被标记为Divide数组的副本到子序列数组的数组,但它不是 - 该问题涉及拆分数组,而这是关于IEnumerable<T>.此外,该问题要求填充最后一个子序列.这两个问题密切相关,但并不相同.
tak*_*gen 62
您可以尝试自己实现上面提到的Batch方法,如下所示:
static class MyLinqExtensions
{
public static IEnumerable<IEnumerable<T>> Batch<T>(
this IEnumerable<T> source, int batchSize)
{
using (var enumerator = source.GetEnumerator())
while (enumerator.MoveNext())
yield return YieldBatchElements(enumerator, batchSize - 1);
}
private static IEnumerable<T> YieldBatchElements<T>(
IEnumerator<T> source, int batchSize)
{
yield return source.Current;
for (int i = 0; i < batchSize && source.MoveNext(); i++)
yield return source.Current;
}
}
Run Code Online (Sandbox Code Playgroud)
我从http://blogs.msdn.com/b/pfxteam/archive/2012/11/16/plinq-and-int32-maxvalue.aspx中抓取了这段代码.
更新:请注意,此实现不仅懒惰地评估批次,而且批次内的项目,这意味着只有在枚举所有以前的批次之后枚举批次时,它才会产生正确的结果.例如:
public static void Main(string[] args)
{
var xs = Enumerable.Range(1, 20);
Print(xs.Batch(5).Skip(1)); // should skip first batch with 5 elements
}
public static void Print<T>(IEnumerable<IEnumerable<T>> batches)
{
foreach (var batch in batches)
{
Console.WriteLine($"[{string.Join(", ", batch)}]");
}
}
Run Code Online (Sandbox Code Playgroud)
将输出:
[2, 3, 4, 5, 6] //only first element is skipped.
[7, 8, 9, 10, 11]
[12, 13, 14, 15, 16]
[17, 18, 19, 20]
Run Code Online (Sandbox Code Playgroud)
因此,如果您使用案例假设批量顺序评估批次,那么上面的懒惰解决方案将起作用,否则如果您不能保证严格顺序批处理(例如,当您想要并行处理批次)时,您可能需要一个解决方案它急切地列举了批量内容,类似于上面的问题或MoreLINQ中提到的内容
L.B*_*L.B 13
也许?
public static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> items, int partitionSize)
{
return items.Select((item, inx) => new { item, inx })
.GroupBy(x => x.inx / partitionSize)
.Select(g => g.Select(x => x.item));
}
Run Code Online (Sandbox Code Playgroud)
还有一个已经实现的:morelinq的Batch.
Jep*_*sen 13
感觉就像你想要两个迭代器块(" yield return方法").我写了这个扩展方法:
static class Extensions
{
public static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> items, int partitionSize)
{
return new PartitionHelper<T>(items, partitionSize);
}
private sealed class PartitionHelper<T> : IEnumerable<IEnumerable<T>>
{
readonly IEnumerable<T> items;
readonly int partitionSize;
bool hasMoreItems;
internal PartitionHelper(IEnumerable<T> i, int ps)
{
items = i;
partitionSize = ps;
}
public IEnumerator<IEnumerable<T>> GetEnumerator()
{
using (var enumerator = items.GetEnumerator())
{
hasMoreItems = enumerator.MoveNext();
while (hasMoreItems)
yield return GetNextBatch(enumerator).ToList();
}
}
IEnumerable<T> GetNextBatch(IEnumerator<T> enumerator)
{
for (int i = 0; i < partitionSize; ++i)
{
yield return enumerator.Current;
hasMoreItems = enumerator.MoveNext();
if (!hasMoreItems)
yield break;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
Run Code Online (Sandbox Code Playgroud)
最疯狂的解决方案(使用Reactive Extensions):
public static IEnumerable<IList<T>> Partition<T>(this IEnumerable<T> items, int partitionSize)
{
return items
.ToObservable() // Converting sequence to observable sequence
.Buffer(partitionSize) // Splitting it on spececified "partitions"
.ToEnumerable(); // Converting it back to ordinary sequence
}
Run Code Online (Sandbox Code Playgroud)
我知道我改变了签名,但无论如何我们都知道我们会将一些固定大小的集合作为一个块.
顺便说一句,如果您将使用迭代器块,请不要忘记将您的实现分成两个方法来急切地验证参数!
对于优雅的解决方案,您还可以查看MoreLinq.Batch。
它将源序列分批处理到大小合适的桶中。
例子:
int[] ints = new int[] {1,2,3,4,5,6};
var batches = ints.Batch(2); // batches -> [0] : 1,2 ; [1]:3,4 ; [2] :5,6
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
32058 次 |
| 最近记录: |