tags:

views:

156

answers:

3

Not the aggregate delta but the delta of each element. Here is some code to explain what I mean:

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));
}

It's the last four lines of code that seem like there might be a more elegant way to do in LINQ somehow.

Cheers,
Berryl

+1  A: 

This post is related and provides an answer.

Obalix
+4  A: 

What you want is the Enumerable.Zip extension method.

An example usage would be:

var delta = oldTotals.Zip(newTotals, (o, n) => n.Amount - o.Amount);

Note that this is new to .NET 4.0. In .NET 3.5 you would have to write your own extension. Something like this:

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);
        }
    }
}
Aaronaught
Cool. Zip doesn't seem like the most intention revealing name to me but at least it's short. When I first saw your answer I thought it was a download! Cheers
Berryl
True, it's not the most discoverable name in the world. I think Eric Lippert coined the term: http://blogs.msdn.com/ericlippert/archive/2009/05/07/zip-me-up.aspx. Either way, it's a useful extension. :)
Aaronaught
the name comes from functional languages. It's called like that because it works like a zipper. By default it should do something like form tuples where the first element comes from list 1 the 2nd from 2.
flq
+3  A: 

As Aaronaught said in his answer, you should use the Zip method ; however, it's not available in .NET 3.5, only in 4.0. Here's a custom implementation :

    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);
            }
        }
    }
Thomas Levesque
Sweet. Are there more extensions like Zip in 4.0?
Berryl
Zip is the only new method in the Enumerable class, but there might be others somewhere...
Thomas Levesque