Linq方式获取列表中元素和下一个元素之间的分段差异

时间:2010-10-19 15:36:15

标签: c# linq

在迭代时是否有Linq方式知道序列中的下一个元素是什么?作为一个具体的例子,假设我有一个整数列表,我想计算每个元素与其后继元素之间的差异,所以例如我希望能够写出

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中的一个简洁的单行程来完成这项工作吗?

2 个答案:

答案 0 :(得分:37)

如果您使用的是.NET 4,则可以ZipSkip

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

答案 1 :(得分:5)

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

假设该列表至少有2个项目。