If I understand you correctly, once you populate the pointsLocal
array, we have the following for each sensor (i,j)
:
this[i][j]
= data from sensor(i,j)
pointsLocal[i,j]
= list of map points for sensor(i,j)
faultyData[i][j]
= true if data from sensor(i,j)
is bad, and is false otherwise
Consider "inverting" your data, so that given a map point (x,y)
you can efficiently
- Find out whether the point is faulty (i.e. any sensor reporting data for the map point is faulty)
- Obtain a list of sensors reporting data correlated with the map point
To do this, we can create a dictionary that uses the comparer that you have already written. Each key is an (x,y)
pair (i.e. an int[2]
) representing a map point; the value returned, if any, is the list of known sensors contributing to that point. A returned value of null
indicates that the map point is "infected" by a faulty sensor and should be ignored. If a given pair does not exist in the dictionary at all, it means no sensors contribute to that point.
var mapPoints = new Dictionary<int[], List<int[]>)(PointsEqualityComparer);
for (int i = 0; i <this.Count; i++)
{
for (int j = 0; j < this[i].Count; j++)
{
foreach (var point in pointsLocal[i,j])
{
if (faultyData[i][j])
{
// infected point
mapPoints[point] = null;
}
else
{
// Add the current sensor's indices (i,j) to the list of
// known sensors for the current map point
List<int[]> sensors = null;
if (!mapPoints.TryGetValue(point, out sensors))
{
sensors = new List<int[]>();
mapPoints[point] = sensors;
}
// null here means that we previously determined that the
// current map point is infected
if (sensors != null)
{
// Add sensor to list for this map point
sensors.Add(new int[] { i, j });
}
}
}
}
}
Now you can enumerate all of the map points, classifying each as good or bad:
var faultyPoints = new List<int[]>(); // not sure you really need this?
var goodPoints = new List<int[]>();
foreach (var point in mapPoints.Keys)
{
var sensors = mapPoints[point];
if (sensors == null)
faultyPoints.Add(point);
else
goodPoints.Add(point);
}
Finally, you could enumerate the sensors for each good map point, to do your analysis:
foreach (var point in goodPoints)
{
var sensors = mapPoints[point];
// for current point, aggregate data for each sensor listed in "sensors"
}
Note that I have not altered allPairsLocal
, because it doesn't seem necessary for the analysis step. However, if you really need to remove the faulty map points from that, you could do that efficiently as well:
for (int i = 0; i <this.Count; i++)
{
for (int j = 0; j < this[i].Count; j++)
{
var points = allPairsLocal[i][j];
var cleanedUp = new List<int[]>();
foreach (var point in points)
{
// Important: do NOT use 'faultyPoints' here. It will kill performance
if (mapPoints[point] != null)
{
cleanedUp.Add(point);
}
}
allPairsLocal[i][j] = cleanedUp;
}
}
The performance improvement in all of this comes from using a Dictionary to look up a single map point whenever you need to know if it is faulty or what its contributing sensors are. The lookup is essentially a constant time operation (amortized), if your hash function is good.
There are a number of optimizations you could make here. For example, do you really need to know the sensor indices to do the aggregations for each map point? Or do you just need the data values? If the latter, then your dictionary would be Dictionary<List<double>>
. Finally, the code could be made more compact by using Linq (instead of loops) to do many of the enumerations.