这是我的版本。它使用Queue 来保存最后一个windowSize 元素,同时枚举源。不幸的是,我不得不使用效率低下的ElementAt Linq 方法在Queue 中查找测试元素,因为Queue 实现没有公开其GetElement 方法(它是内部的)。对于小窗口尺寸,这应该不是问题。
public static IEnumerable<(int, TSource)> LocalMaxima<TSource>(
this IEnumerable<TSource> source, int windowSize)
{
var comparer = Comparer<TSource>.Default;
var queue = new Queue<TSource>();
var testedQueueIndex = (windowSize - 1) / 2;
var index = testedQueueIndex;
foreach (var item in source)
{
queue.Enqueue(item);
if (queue.Count >= windowSize)
{
var testedItem = queue.ElementAt(testedQueueIndex);
var queueIndex = 0;
foreach (var queuedItem in queue)
{
if (queueIndex != testedQueueIndex
&& comparer.Compare(queuedItem, testedItem) > 0) goto next;
queueIndex++;
}
yield return (index, testedItem);
next:
queue.Dequeue();
index++;
}
}
}
使用示例:
var source = "abbacdbbcac".ToCharArray();
var indexes = Enumerable.Range(0, source.Length);
var result = source.LocalMaxima(5);
Console.WriteLine($"Source: {String.Join(", ", source)}");
Console.WriteLine($"Indexes: {String.Join(" ", indexes)}");
Console.WriteLine($"Result: {String.Join(", ", result)}");
输出:
Source: a, b, b, a, c, d, b, b, c, a, c
Indexes: 0 1 2 3 4 5 6 7 8 9 10
Result: (5, d), (8, c)