Working in C#, I need to find all local peaks in a List of doubles and return them as another List doubles. This seems simple enough if I have a set number of values I\'m co
Here is my version. It uses a Queue to hold the last windowSize elements, while enumerating the source. Unfortunately I had to use the inefficient ElementAt Linq method to find the tested element in the Queue, because the Queue implementation does not expose its GetElement method (it is internal). For small window sizes this should not be a problem.
public static IEnumerable<(int, TSource)> LocalMaxima(
this IEnumerable source, int windowSize)
{
var comparer = Comparer.Default;
var queue = new Queue();
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++;
}
}
}
Usage example:
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)}");
Output:
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)