My task is to implement the GetNeighbors method, which returns from a set of points only points that are h-neighbors for a point with integer coordinates x and y. (read the summary in code for more understandment)
Actually, I have the same task as this guy Find k nearest neighbor in C#, but the answer there doesn't seem to work. And I think of doing it just with loops like it should be expected of me I guess :)>.
Now my code so far:
/// <summary>
/// Gets from a set of points only points that are h-neighbors for a point with integer coordinates x and y.
/// </summary>
/// <param name="point">Given point with integer coordinates x and y.</param>
/// <param name="h">Distance around a given point.</param>
/// <param name="points">A given set of points.</param>
/// <returns>Only points that are h-neighbors for a point with integer coordinates x and y.</returns>
/// <exception cref="ArgumentNullException">Throw when array points is null.</exception>
/// <exception cref="ArgumentException">Throw when h-distance is less or equals zero.</exception>
public static Point[] GetNeighbors(Point point, int h, params Point[] points)
{
if (points is null)
{
throw new ArgumentNullException(nameof(points));
}
if (h <= 0)
{
throw new ArgumentException(null);
}
List<Point> neighbors = new List<Point>();
int left = point.X - h;
int right = point.X h;
int bottom = point.Y - h;
int top = point.Y h;
for (int y = top; y <= bottom; y )
{
for (int x = left; x <= right; x )
{
// Yeah...
}
}
return neighbors.ToArray();
}
So what I have done so far is found the top, bottom, left and right borders in the neighborhood. What I think I only need to do is a if statement that could compare both the point I have and from the points array. Hm how to do that, I am not very familiar with using structs, everytime is a failure.
This is how struct Point was built:
/// <summary>
/// Represents a point on the coordinate plane.
/// </summary>
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;
}
}
CodePudding user response:
You must not loop over the coordinates but over the points. Here is a solution using LINQ:
public static Point[] GetNeighbors(Point point, int h, params Point[] points)
{
int minX = point.X - h;
int maxX = point.X h;
int minY = point.Y - h;
int maxY = point.Y h;
return points
.Where(p => p.X >= minX && p.X <= maxX && p.Y >= minY && p.Y <= maxY)
.ToArray();
}
With C# 9.0 you can simplify the comparison with pattern matching
.Where(p => p.X is >=minX and <=maxX && p.Y is >=minY and <=maxY)
Here is a solution using an explicit loop. Since we don't know the size of the resulting array, I am storing the result in a list:
...
var list = new List<Point>();
foreach (Point p in points) {
if (p.X is >=minX and <=maxX && p.Y is >=minY and <=maxY) {
list.Add(p);
}
}
return list.ToArray();
Or you could return a list instead.
Yet another solution is to use an iterator method:
public static IEnumerable<Point> GetNeighbors(Point point, int h, params Point[] points)
{
int minX = point.X - h;
int maxX = point.X h;
int minY = point.Y - h;
int maxY = point.Y h;
foreach (Point p in points) {
if (p.X is >=minX and <=maxX && p.Y is >=minY and <=maxY) {
yield return p;
}
}
}
Note that this approach does not store the points in a collection, instead, the loop inside the method is executed as you loop over the result (explicitly in a foreach-loop or implicitly by applying .ToArray()
or .Count()
etc.).
Point[] result = GetNeighbors(center, 2, p1, p2, p3, p4).ToArray();