简体   繁体   中英

Find k nearest neighbor in C#

Gets from a set of points only points that are h-neighbors for a point with integer coordinates x and y. "point" Given point with integer coordinates x and y. "h" Distance around a given point. "points" A given set of points.

class Point:

public readonly struct Point : System.IEquatable<Point>
{
    public Point(int x, int y)
    {
        this.X = x;
        this.Y = y;
    }


    public int X { get; }

    public int Y { get; }
    
    public static bool operator ==(Point left, Point right)
    {
        return left.Equals(right);
    }
    
    public static bool operator !=(Point left, Point right)
    {
        return !(left == right);
    }
    
    public override int GetHashCode()
    {
        return this.X.GetHashCode() ^ this.Y.GetHashCode();
    }
    
    public override bool Equals(object obj)
    {
        if (obj is null)
        {
            return false;
        }

        if (!(obj is Point))
        {
            return false;
        }

        if (obj.GetType() != this.GetType())
        {
            return false;
        }

        Point point = (Point)obj;
        
        return this.Equals(point);
    }
    public bool Equals(Point other)
    {
        return this.X == other.X && this.Y == other.Y;
    }
}

Method:

public static Point[] GetNeighbors(Point point, int h, params Point[] points)
    {
      
    }

I don't know how to solve this problem, I tried to solve it using:

 for (int i = 0; i <= points.Length - 1; i++)
        {
            PointsCoordinate[i] = Math.Sqrt(Math.Pow(points[i].X, 2) + Math.Pow(points[i].Y, 2));
        }

After that I will find nearest values of point using list or et cetera, but in this case I have to return exactly nearest points from array not values, how can I solve this, mb I have the wrong approach to solving this problem. I need to connect sorted values with Points in array, help me please

First you need to calculate the distance from your source "point" to each of your neighbor points. You can do that by using Pythagorean theorem :

在此处输入图像描述

The sum of the areas of the two squares on the legs (a and b) equals the area of the square on the hypotenuse.

public static double CalculateDistanceBetweenPoints(Point originPoint, Point destinationPoint)
{
    return Math.Pow(originPoint.X - destinationPoint.X, 2)
        + Math.Pow(originPoint.Y - destinationPoint.Y, 2);
}

You can calculate the distance for each of the points using LINQ extension method Select() :

var pointsWithDistance = points
    .Select(p => new { Point = p, Distance = CalculateDistanceBetweenPoints(point, p) });

Then filter out the neighbors that are outside the "h" distance with Where() :

var filteredPointsWithDistance = points
    .Select(p => new { Point = p, Distance = CalculateDistanceBetweenPoints(point, p) })
    .Where(pointAndDistance => pointAndDistance.Distance <= Math.Pow(h, 2));

...and order them by growing distance:

var orderedFilteredPointsWithDistance = points
    .Select(p => new { Point = p, Distance = CalculateDistanceBetweenPoints(point, p) })
    .Where(pointAndDistance => pointAndDistance.Distance <= Math.Pow(h, 2))
    .OrderBy(pointAndDistance => pointAndDistance.Distance);

The calculated distance is no longer needed, bring back the Point , use Select() again:

var points = points
    .Select(p => new { Point = p, Distance = CalculateDistanceBetweenPoints(point, p) })
    .Where(pointAndDistance => pointAndDistance.Distance <= Math.Pow(h, 2))
    .OrderBy(pointAndDistance => pointAndDistance.Distance)
    .Select(pointAndDistance => pointAndDistance.Point);

Finally, create an array from the resulted sequence of points:

return points
    .Select(p => new { Point = p, Distance = CalculateDistanceBetweenPoints(point, p) })
    .Where(pointAndDistance => pointAndDistance.Distance <= Math.Pow(h, 2))
    .OrderBy(pointAndDistance => pointAndDistance.Distance)
    .Select(pointAndDistance => pointAndDistance.Point)
    .ToArray();

The whole code and usage example:

public static class Program
{
    public static void Main()
    {
        var h = 10;
        var sourcePoint = new Point(0, 0);
        var neighbors = new Point[]
        {
            new Point(0, 0),
            new Point(100, 100),
            new Point(10, 0),
            new Point(5, 5),
            new Point(-2, -2),
        };
        var nearestNeighbors = GetNeighbors(sourcePoint, h, neighbors);
    }

    public static Point[] GetNeighbors(Point point, int h, params Point[] points)
    {
        return points
            .Select(p => new { Point = p, Distance = CalculateDistanceBetweenPoints(point, p) })
            .Where(pointAndDistance => pointAndDistance.Distance <= Math.Pow(h, 2))
            .OrderBy(pointAndDistance => pointAndDistance.Distance)
            .Select(pointAndDistance => pointAndDistance.Point)
            .ToArray();
    }

    public static double CalculateDistanceBetweenPoints(Point originPoint, Point destinationPoint)
    {
        return Math.Pow(originPoint.X - destinationPoint.X, 2)
            + Math.Pow(originPoint.Y - destinationPoint.Y, 2);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM