Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在Linq查询中计算一系列整数的运行和?_C#_Linq - Fatal编程技术网

C# 如何在Linq查询中计算一系列整数的运行和?

C# 如何在Linq查询中计算一系列整数的运行和?,c#,linq,C#,Linq,我试图提出一个linq查询,将一个IEnumerable转换为另一个IEnumerable,其中结果中的每个int是从初始列表到该位置的所有int的总和: 给定int[]a 我需要int[]b 其中b[0]=a[0],b[1]=a[0]+a[1],b[2]=a[0]+a[1]+a[2]等等 或者,上面的总和可以写成b[1]=b[0]+a[1],b[2]=b[1]+a[2]等等,但我看不出这有什么帮助 当然,我可以通过for循环来实现这一点,但是我从查询中获得了a[]序列,我认为如果我继续查询,而

我试图提出一个linq查询,将一个
IEnumerable
转换为另一个
IEnumerable
,其中结果中的每个int是从初始列表到该位置的所有int的总和:

给定
int[]a

我需要
int[]b

其中
b[0]=a[0],b[1]=a[0]+a[1],b[2]=a[0]+a[1]+a[2]
等等

或者,上面的总和可以写成
b[1]=b[0]+a[1],b[2]=b[1]+a[2]
等等,但我看不出这有什么帮助


当然,我可以通过
for
循环来实现这一点,但是我从查询中获得了a[]序列,我认为如果我继续查询,而不是突然在那里为
添加
,)

好吧,你可以很容易地完成它,但会有副作用,尽管它很讨厌

int sum = 0;
int[] b = a.Select(x => (sum += x)).ToArray();

如果框架提供了一种“运行聚合”来封装这一点,那就太好了,但据我所知,它并没有。这类似于Haskell的函数

public static IEnumerable<TResult> Scan<T, TResult>(
    this IEnumerable<T> source, 
    Func<T, T, TResult> combine)
{
    using (IEnumerator<T> data = source.GetEnumerator())
        if (data.MoveNext())
        {
            T first = data.Current;

            yield return first;

            while (data.MoveNext())
            {
                first = combine(first, data.Current);
                yield return first;
            }
        }
}

int[] b = a
    .Scan((running, current) => running + current)
    .ToArray();
公共静态IEnumerable扫描(
这是一个数不清的来源,
Func(联合收割机)
{
使用(IEnumerator data=source.GetEnumerator())
if(data.MoveNext())
{
T first=数据。当前;
收益率优先;
while(data.MoveNext())
{
first=联合收割机(first,data.Current);
收益率优先;
}
}
}
int[]b=a
.扫描((运行,当前)=>运行+当前)
.ToArray();

替代Skeet先生的解决方案:如果我们放弃linq查询的要求,更确切地说是“将一个
IEnumerable
转换为另一个
IEnumerable
”,我们可以使用以下方法:

    static IEnumerable<int> Sum(IEnumerable<int> a)
    {
        int sum = 0;
        foreach (int i in a)
        {
            sum += i;
            yield return sum;
        }
    }

如果您不想一次创建整个阵列,这也很有用。

上述答案不太有效……并且与Haskell的scanl的签名不相同。。。。 基本上,它是linq“聚合”思想的扩展……我认为这与Haskell实现更匹配

    public static IEnumerable<TResult> Scanl<T, TResult>(
        this IEnumerable<T> source,
        TResult first,
        Func<TResult, T, TResult> combine)
    {
        using (IEnumerator<T> data = source.GetEnumerator())
        {
            yield return first;

            while (data.MoveNext())
            {
                first = combine(first, data.Current);
                yield return first;
            }
        }
    }

你真是太棒了:)是的,它有点讨厌,但它已经足够好了,我最近正在寻求删除for语句。是的,我使用数组语法是因为它更容易解释需求,但该参数实际上是一个IEnumerable。但是,Skeet先生在这种情况下仍然可以工作,只是没有.ToArray()调用,而且它更紧凑,所以我仍然投票支持:)您在
中遇到了一个问题,即首先返回
,如果是类型T,则首先返回,而不是TResult
    public static IEnumerable<TResult> Scanl<T, TResult>(
        this IEnumerable<T> source,
        TResult first,
        Func<TResult, T, TResult> combine)
    {
        using (IEnumerator<T> data = source.GetEnumerator())
        {
            yield return first;

            while (data.MoveNext())
            {
                first = combine(first, data.Current);
                yield return first;
            }
        }
    }
    [TestMethod]
    public void Scanl_Test()
    {
        var xs = new int[] { 1, 2, 3, 4, 5, 6, 7 };

        var lazyYs = xs.Scanl(0, (y, x) => y + x);

        var ys = lazyYs.ToArray();

        Assert.AreEqual(ys[0], 0);
        Assert.AreEqual(ys[1], 1);
        Assert.AreEqual(ys[2], 3);
        Assert.AreEqual(ys[3], 6);
        Assert.AreEqual(ys[4], 10);
        Assert.AreEqual(ys[5], 15);
        Assert.AreEqual(ys[6], 21);
        Assert.AreEqual(ys[7], 28);
    }