private static List <Neighbor> GetNeighborsByDistance(LeafNode leafNode, IDictionary <int, List <LeafNode> > buckets, IDistanceMetric distanceMetric) { var neighbors = distanceMetric.SignificantCoordinates(leafNode.Coords) // Get every node with at least one shared match in common .SelectMany(coord => buckets.TryGetValue(coord, out var bucket) ? bucket : Enumerable.Empty <LeafNode>()) // We only need one direction A -> B (not also B -> A) since we're ultimately going to look at the smallest distances. .Where(neighborNode => neighborNode.Index < leafNode.Index) // Make sure that each node is considered only once (might have been in more than one bucket if more than one shared match in common. .Distinct() .Select(neighborNode => new Neighbor(neighborNode, leafNode)) .LowestN(neighbor => neighbor.DistanceSquared, _maxNeighbors) .ToList(); return(neighbors); }
private static async Task CalculateNeighborsAsync(List <LeafNode> leafNodesAll, List <LeafNode> leafNodesToRecalculate, IDistanceMetric distanceMetric, ProgressData progressData) { var buckets = leafNodesAll .SelectMany(leafNode => distanceMetric.SignificantCoordinates(leafNode.Coords).Select(coord => new { Coord = coord, LeafNode = leafNode })) .GroupBy(pair => pair.Coord, pair => pair.LeafNode) .ToDictionary(g => g.Key, g => g.ToList()); var calculateNeighborsByDistanceTasks = leafNodesToRecalculate.Select(async leafNode => { leafNode.NeighborsByDistance = await Task.Run(() => GetNeighborsByDistance(leafNode, buckets, distanceMetric)); progressData?.Increment(); }); await Task.WhenAll(calculateNeighborsByDistanceTasks); }