如何通过 Linq 将集合拆成多个块?

咨询区

  • BlakeH

请问是否可以用 linq 按序生成带有多个固定 size 的块?我的理想情况下还可以对这些 进行操作。

回答区

  • Sergey Berezovskiy

说实话,你不需要写任何代码,使用 MoreLINQ 中的批次方法即可,它可以按序拆解到固定大小的桶中,你可以直接在 Nuget 上安装 MoreLINQ 包。

int size = 10;
var batches = sequence.Batch(size);

如果你好奇它的实现方法,可参考如下源码:

public static IEnumerable<IEnumerable<TSource>> Batch<TSource>(
                  this IEnumerable<TSource> source, int size)
{
    TSource[] bucket = null;
    var count = 0;

    foreach (var item in source)
    {
        if (bucket == null)
            bucket = new TSource[size];

        bucket[count++] = item;
        if (count != size)
            continue;

        yield return bucket;

        bucket = null;
        count = 0;
    }

    if (bucket != null && count > 0)
        yield return bucket.Take(count).ToArray();
}
  • dana

这个需求确实比较常见,在 .NET6 中添加了一个 Enumerable.Chunk() 扩展方法,然后你就可以像下面这样使用。

var list = new List<int> { 1, 2, 3, 4, 5, 6, 7 };

var chunks = list.Chunk(3);
// returns { { 1, 2, 3 }, { 4, 5, 6 }, { 7 } }

如果你对源码感兴趣,可以参考如下:

public static IEnumerable<TSource[]> Chunk<TSource>(this IEnumerable<TSource> source, int size)
{
 if (source == null)
 {
  ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source);
 }
 if (size < 1)
 {
  ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.size);
 }
 return ChunkIterator(source, size);
}

private static IEnumerable<TSource[]> ChunkIterator<TSource>(IEnumerable<TSource> source, int size)
{
 using IEnumerator<TSource> e = source.GetEnumerator();
 while (e.MoveNext())
 {
  TSource[] array = new TSource[size];
  array[0] = e.Current;
  int i;
  for (i = 1; i < array.Length; i++)
  {
   if (!e.MoveNext())
   {
    break;
   }
   array[i] = e.Current;
  }
  if (i == array.Length)
  {
   yield return array;
   continue;
  }
  Array.Resize(ref array, i);
  yield return array;
  break;
 }
}

点评区

发现 .NET6 下的 Enumerable 增加了一些 By 系列方法:MinBy,ExceptBy,IntersectBy,又有得学了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值