使用 Linq 按索引求和

本文关键字:求和 索引 Linq 使用 | 更新日期: 2023-09-27 18:17:51

我有一个有 96 个值的集合。我想对 4 个连续索引的值求和。如何使用 Linq 执行此操作?

collection = {100, 101, 200, 150, 103, 105, 100, 104,  .........., 20, 40, 60, 80};

(100, 101, 200, 150;)的总和然后是(103, 105, 100, 104;)的总和...然后(20, 40, 60, 80;)之和 这意味着现在我的新集合将有 24 个值。

如何使用 Linq 执行此操作?

使用 Linq 按索引求和

我们可以从这个实用程序函数开始,根据给定的批量大小Batch项目:

public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> source, int batchSize)
{
    List<T> buffer = new List<T>(batchSize);
    foreach (T item in source)
    {
        buffer.Add(item);
        if (buffer.Count >= batchSize)
        {
            yield return buffer;
            buffer = new List<T>(batchSize);
        }
    }
    if (buffer.Count > 0)
    {
        yield return buffer;
    }
}

之后,它就像

var query = data.Batch(4)
    .Select(batch => batch.Sum());
您可以

index/4分组以获得总和,如下所示:

var res = collection
    .Select((v,i) => new {v, i})
    .GroupBy(p => p.i / 4)
    .Select(g => g.Sum(p.v));

您可以从索引中计算组索引,并在此基础上进行分组,并从每个组中的值中获取总和:

var sums = collection
.Select((n, i) => new { Group = i / 4, Value = n })
.GroupBy(x => x.Group)
.Select(g => g.Sum(y => y.Value));

您需要一个新的扩展方法Partition

public static IEnumerable<IEnumerable<T>> Partition<T>(
    this IEnumerable<T> source, int partitionSize)
{
    var counter = 0;
    var result = new T[partitionSize];
    foreach(var item in source)
    {
        result[counter] = item;
        ++counter;
        if(counter >= partitionSize)
        {
            yield return result;
            counter = 0;
            result = new T[partitionSize];
        }
    }
    if(counter != 0)
        yield return result.Take(counter);
}

用法将是:

collection.Partition(4).Select(x => x.Sum())

这是Servy发布的Batch方法的另一种方法。

首先,找到一种方法来按索引对集合进行分组。在这种情况下,我选择使用整数除法使元素 0-3 组 0,4-7 组 1,依此类推。

接下来,将元素分组到需要求和的不同集合中(通过分组键(。

最后,选择属于每个组的元素的总和。

values.Select((x, i) => new { GroupingKey = i/4, Value = x })
      .GroupBy(x => x.GroupingKey)
      .Select(x => new { Group = x.Key, Sum = x.Sum() });
这样做

static IEnumerable<int> BatchSum(int batchSize, IEnumerable<int> collection)
{
    var batch = collection.Take(batchSize).ToList();
    if (batch.Count == 0) yield break;
    yield return batch.Sum();
    var rest = collection.Skip(batchSize);
    foreach (var sum in BatchSum(batchSize, rest)) yield return sum;
}

并使用它:

var collection = new[] { 100, 101, 200, 150, 103, 105, 100, 104, 20, 40, 60, 80, 11, 13 };
foreach (var sum in BatchSum(4, collection)) Show(sum);

输出将是:

551
412
200
24

如您所见,您的收藏长度不必是batchSize的因素。