Если вы используете .NET 4.0, это должно работать нормально:
var deltas = list.Zip(list.Skip(1), (current, next) => next - current);
Помимо нескольких перечислителей, это довольно эффективно; он должен хорошо работать на любой последовательности.
Вот альтернатива .NET 3.5:
var deltas = list.Skip(1)
.Select((next, index) => next - list[index]);
Очевидно, что эта идея будет эффективной только при использовании индексатора списка. Изменение его для использования ElementAt
может не быть хорошей идеей: квадратичное время выполнения будет происходить для не IList<T>
последовательностей. В этом случае написание пользовательского итератора является хорошим решением.
РЕДАКТИРОВАТЬ : Если вам не нравится идея Zip
+ Skip(1)
, написание такого расширения (непроверенного) может оказаться полезным в таких ситуациях:
public class CurrentNext<T>
{
public T Current { get; private set; }
public T Next { get; private set; }
public CurrentNext(T current, T next)
{
Current = current;
Next = next;
}
}
...
public static IEnumerable<CurrentNext<T>> ToCurrentNextEnumerable<T>(this IEnumerable<T> source)
{
if (source == null)
throw new ArgumentException("source");
using (var source = enumerable.GetEnumerator())
{
if (!enumerator.MoveNext())
yield break;
T current = enumerator.Current;
while (enumerator.MoveNext())
{
yield return new CurrentNext<T>(current, enumerator.Current);
current = enumerator.Current;
}
}
}
Который вы могли бы затем использовать как:
var deltas = list.ToCurrentNextEnumerable()
.Select(c=> c.Next - c.Current);