27

Is there a Linq way of knowing what the next element in the sequence is while iterating? As a concrete example, say I have a list of ints, and I want to calculate the difference between each element and its successor, so for example I would like to be able to write

var myList = new List<int>() { 1,3,8,2,10 };
var differences = myList.Select( ml => ml.Next() - ml ) // pseudo-code, obviously

where the result I want is a list { 2,5,-6,8 }.

Obviously this is trivial in a for loop, but can anyone think of a neat one-liner in Linq to do this job?

Aidan
  • 4,783
  • 5
  • 34
  • 58

2 Answers2

49

If you're using .NET 4 then you could Zip and Skip:

var differences = myList.Zip(myList.Skip(1), (x, y) => y - x);

If you're using an older version of the framework, and/or you wanted a slightly more efficient way of doing this, then you could create a simple extension method:

var differences = myList.Pairwise((x, y) => y - x);

// ...

public static class EnumerableExtensions
{
    public static IEnumerable<T> Pairwise<T>(
        this IEnumerable<T> source, Func<T, T, T> selector)
    {
        if (source == null) throw new ArgumentNullException("source");
        if (selector == null) throw new ArgumentNullException("selector");

        using (var e = source.GetEnumerator())
        {
            if (!e.MoveNext()) throw new InvalidOperationException("Sequence cannot be empty.");

            T prev = e.Current;

            if (!e.MoveNext()) throw new InvalidOperationException("Sequence must contain at least two elements.");

            do
            {
                yield return selector(prev, e.Current);
                prev = e.Current;
            } while (e.MoveNext());
        }
    }
}
LukeH
  • 263,068
  • 57
  • 365
  • 409
7
var differences = myList
    .Take(myList.Count - 1)
    .Select((v, i) => myList[i + 1] - v);

Assuming the list has at least 2 items.

Yuriy Faktorovich
  • 67,283
  • 14
  • 105
  • 142
  • Please, be aware that this solution works on indexed lists only, while the Zip solution (given in https://stackoverflow.com/a/3970131/637968) works on generic IEnumerable sequences. – Mike Jun 07 '19 at 11:27