Это будет работать, если интервал известен, если у вас есть доступ к методу Zip (поставляется с .NET 4):
list.Zip(list.Skip(1), (x,y) => new { x, delta = y - x })
.SelectMany(a => Enumerable.Range(1, a.delta/interval - 1)
.Select(i => a.x + i*interval));
Обратите внимание, что это повторяет список дважды, поэтому в случае, если источник является ленивым перечислимым, вам нужно сначала его буферизовать. Эта конструкция с Zip
и Skip
- это быстрый и грязный способ проецирования последовательных элементов вместе. Библиотека System.Interactive Reactive Extensions имеет метод Scan
для этого, и Джон показал возможную реализацию в другом ответе . Ни один из них не повторяет список дважды, так что это был бы гораздо лучший выбор.
Если интервал должен быть определен, вы можете получить минимальную дельту:
var deltas = list.Zip(list.Skip(1), (x,y) => y - x );
var interval = deltas.Min();
list.Zip(deltas, (x, delta) => new { x, delta })
.SelectMany(a => Enumerable.Range(1, a.delta/interval - 1)
.Select(i => a.x + i*interval));
Есть некоторые предположения, которые я сделал, хотя:
- все различия между элементами кратны интервалу;
- вход отсортирован.
Как это работает:
- Сначала он строит последовательность пар с каждым элементом, кроме последнего и интервалом до элемента, который следует за ним;
- Затем для каждой из этих пар создаются все пропущенные значения в дельте: в каждой дельте есть ровно
a.delta/interval - 1
значений, и каждое из них находится на определенном количестве интервалов от хранилища элементов в паре, следовательно a.x + i*interval
.
SelectMany
заботится о сведении всех этих последовательностей пропущенных значений в одно целое.