Reputation: 167
I'm trying to find indices for all contiguous elements that occurrence more than Threshold in one dimensional integer array using c#
double[] x = new double[20]{1,1,0,0,0,0,1,1,0,0,0,0,1,1,1,0,0,0,1,1};
I want to get indices for this x[] vector as the following for 0 values
threshold=4
start-index[0] =2
end-index[0] =5
start-index[1] =8
end-index[1] =11
i try to use this code, but there is many problems in it
public void myFunc(double[] x, ref List<int> start, ref List<int> end,int matchingVal,int threshold)
{
int count = 0;
for (int i = 0; i < x.Length; i++)
{
for (int j = i+1; j < threshold; j++)
{
if (x[i] == x[j] && x[i] == matchingVal)
{
count++;
}
else
{
break;//no contiguous element
}
if (count >= threshold)
{
start.Add(i);
end.Add(i + count);
count = 0;
}
else
continue;
}
}
}
Upvotes: 0
Views: 302
Reputation: 81493
Updated added more tests and fixed an issue thanks to @AntonínLejsek
Given
public static IEnumerable<(int start, int finish)> GetStuff(int thresh, double[] ary)
{
int start = 0, count = 1;
for (var i = 0; i < ary.Length - 1; i++, count++)
if (ary[i] == ary[i + 1])
{
if (count == 1) start = i;
}
else
{
if (count >= thresh) yield return (start, i);
count = 0;
}
if (count >= thresh) yield return (start, ary.Length-1);
}
Usage
foreach (var tuple in GetStuff(3,ary))
Console.WriteLine($"start : {tuple.start}, finish : {tuple.finish}");
Output
var ary = new double[] { 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1 };
start : 2, finish : 5
start : 8, finish : 11
start : 12, finish : 14
start : 15, finish : 17
var ary = new double[] { 1, 1, 1 ,0 };
start : 0, finish : 2
var ary = new double[] { 1, 1, 1 };
start : 0, finish : 2
Upvotes: 1
Reputation: 23898
If you are willing to use MoreLINQ, consider using GroupAdjacent
.
An example is below. Basically, it takes the original array, uses Select
to include the index, uses GroupAdjacent
to group adjacent values together, uses Where
and Count
to check there are at least 4 adjacent values, then uses Select
to project an anonymous type including the value and its first and last index (this can be changed to project to whatever concrete type you want). Then string.Join
is used to write it to the console so you can see the results.
using System;
using System.Linq;
using MoreLinq;
namespace Test
{
class Program
{
static void Main(string[] args)
{
double[] x = new double[20] { 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1 };
var results = x.Select((value, index) => new { value, index })
.GroupAdjacent(z => z.value)
.Where(z => z.Count() >= 4)
.Where(z => z.Key == 0) // it is unclear whether you want to filter for specific values - if so, this is how to do it
.Select(z =>
new { value = z.Key, firstIndex = z.First().index, lastIndex = z.Last().index })
.ToList();
Console.WriteLine(string.Join(Environment.NewLine, results.Select(z => $"{z.value} - {z.firstIndex} - {z.lastIndex}")));
Console.ReadLine();
}
}
}
Upvotes: 3