我可以在LINQ中获得两个IEnumerables的增量吗?

Ber*_*ryl 8 c# linq

不是总增量,而是每个元素的增量.这里有一些代码来解释我的意思:

var deltaTotals = _deltaEnumerable.Select(a => a.Amount).ToList();
var oldTotals = _totalsEnumerable.Select(d => d.Amount).ToList();

// trigger change in _totalsEnumerable

// ** can LINQ do the lines below 
var newTotals = totalsEnumerable.Select(d => d.Amount);
for (var i = 0; i < 7; i++) {
    var newAmount = oldTotals[i] - deltaTotals[i];
    Assert.That(newTotals.ElementAt(i), Is.EqualTo(newAmount));
}
Run Code Online (Sandbox Code Playgroud)

这是最后四行代码,似乎在某种程度上可能有更优雅的方式在LINQ中做.

干杯,
Berryl

Aar*_*ght 7

你想要的是Enumerable.Zip扩展方法.

一个示例用法是:

var delta = oldTotals.Zip(newTotals, (o, n) => n.Amount - o.Amount);
Run Code Online (Sandbox Code Playgroud)

请注意,这是.NET 4.0的新增功能.在.NET 3.5中,您必须编写自己的扩展.像这样的东西:

public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(
    this IEnumerable<TFirst> first,
    IEnumerable<TSecond> second,
    Func<TFirst, TSecond, TResult> resultSelector)
{
    using (var firstEnumerator = first.GetEnumerator())
    using (var secondEnumerator = second.GetEnumerator())
    {
        while ((firstEnumerator.MoveNext() && secondEnumerator.MoveNext()))
        {
            yield return resultSelector(firstEnumerator.Current,
                secondEnumerator.Current);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这个名字来自功能语言.之所以这样称呼它是因为它像拉链一样工作.默认情况下,它应该执行类似表单元组的操作,其中第一个元素来自列表1,第二个元素来自2. (2认同)

Tho*_*que 5

正如Aaronaught在答案中所说,你应该使用这种Zip方法; 但是,它在.NET 3.5中不可用,仅在4.0中可用.这是一个自定义实现:

    public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> selector)
    {
        if (first == null)
            throw new ArgumentNullException("first");
        if (second == null)
            throw new ArgumentNullException("second");
        if (selector == null)
            throw new ArgumentNullException("selector");

        return first.ZipIterator(second, selector);
    }

    private static IEnumerable<TResult> ZipIterator<TFirst, TSecond, TResult>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> selector)
    {
        using (var enum1 = first.GetEnumerator())
        using (var enum2 = second.GetEnumerator())
        {
            while (enum1.MoveNext() && enum2.MoveNext())
            {
                yield return selector(enum1.Current, enum2.Current);
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)