Подтвердить что ты не робот

Linq способ получить кусочную разницу между элементом и следующим элементом в списке

Есть ли способ Linq знать, что следующий элемент в последовательности во время итерации? В качестве конкретного примера, скажем, у меня есть список ints, и я хочу рассчитать разницу между каждым элементом и его преемником, поэтому, например, я бы хотел написать

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

где я хочу получить список {2,5, -6,8}.

Очевидно, что это тривиально в цикле for, но может ли кто-нибудь подумать о аккуратном однострочном в Linq для выполнения этой работы?

4b9b3361

Ответ 1

Если вы используете .NET 4, вы можете Zip и Skip:

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

Если вы используете более старую версию фреймворка и/или хотите немного более эффективный способ сделать это, вы можете создать простой метод расширения:

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

Ответ 2

var differences = myList
    .Take(myList.Count - 1)
    .Select((v, i) => myList[i + 1] - v);

Предполагая, что список имеет не менее 2 элементов.