Finding n number of closest points in a list - c#

C# beginner here, working with Grasshopper for Rhino so some object types are a little strange.
I am currently trying to find n number of closest points within a list to a given point. I am able to find the closest point using the following function, but cannot adapt it to retrieve multiple closest points.
public Vec3D ClosestPoint(Vec3D a, List<Vec3D>points){
List<float> distanceList = new List<float>();
for (int i = 0; i < points.Count(); i++){
float distanceFloat = a.distanceTo(points[i]);
distanceList.Add(distanceFloat);
}
int smallestIndex = distanceList.IndexOf(distanceList.Min());
return points[smallestIndex];
}
How would I adapt this code for the below function, where n is how many closest points to find?
public Vec3D ClosestPoints(Vec3D a, List<Vec3D>points, int n){
}

You can use Linq to get that result:
public IEnumerable<Vec3D> ClosestPoints(Vec3D a, List<Vec3D>points, int n) =>
points.Select(point => new
{
point = point,
distance = a.distanceTo(point)
}).
OrderBy(x = x.distance).
Take(n).
Select(x => x.point);
Note that in this case, the other method becomes:
public Vec3D ClosestPoint(Vec3D a, List<Vec3D>points) =>
ClosestPoints(a, points, 1).FirstOrDefault();

Related

C# - How to place a given number of random mines in an array

I'm new to c#. I have a task to make a type of minesweeper, but which immediately opens a solution.
static void Main(string[] args)
{
Console.Write("Enter the width of the field: ");
int q = Convert.ToInt32(Console.ReadLine());
Console.Write("Enter the length of the field: ");
int w = Convert.ToInt32(Console.ReadLine());
Console.Write("Enter the number of bombs: ");
int c = Convert.ToInt32(Console.ReadLine());
Random rand = new Random();
var charArray = new char[q, w];
var intArray = new int[q, w];
for (int i = 0; i < q; i++)
{
for (int j = 0; j < w; j++)
{
intArray[i, j] = rand.Next(2);
charArray[i, j] = intArray[i, j] == 0 ? '_' : '*';
Console.Write(charArray[i, j]);
}
Console.WriteLine();
}
}
}
}
Two arrays should be output. Everything should be closed on the first one, that is, there should be only the characters: _ and *
0 - these are places without mines, I replaced them with a symbol _
1 - these are places with mines, I replaced them with an asterisk symbol, but they do not accept the number of mines entered by the user. And it is necessary that there are as many "*" characters as there are mines.
And in the second array there should be an already open solution of the game. That is, the cells next to which there are mines should take a number meaning the number of mines next to this cell.
Please help me..
Compiling the current code
Random random = new Random();
while(c > 0)
{
var rq = random.Next(q);
var rw = random.Next(w);
if(intArray[rq,rw] == 0)
{
intArray[rq, rw] = 1;
c--;
}
}
I would suggest dividing the problem in smaller manageable chunks. For instance, you can place the bombs in a initial step, and on a second step build the solution. You can build the solution at the same time you place the bombs, although for clarity you can do it after.
Naming of variables is also important. If you prefer using single letter variable names, I believe that's fine for the problem limits, however I would use meaningful letters easier to remember. eg: W and H for the width and height of the board, and B for the total number of bombs.
The first part of the problem then can be described as placing B bombs in a WxH board. So instead of having nested for statements that enumerate WxH times, it's better to have a while loop that repeats the bomb placing logic as long as you have remaining bombs.
Once you generate a new random location on the board, you have to check you haven't placed a bomb there already. You can have an auxiliary function HasBomb that checks that:
bool HasBomb(char[,] charArray, int x, int y)
{
return charArray[x,y] == '*';
}
I'll leave error checking out, this function being private can rely on the caller sending valid coordinates.
Then the bomb placing procedure can be something like:
int remainingBombs = B;
while (remainingBombs > 0)
{
int x = rand.Next(W);
int y = rand.Next(H);
if (!HasBomb(charArray, x, y)
{
charArray[x,y] = '*';
remainingBombs--;
}
}
At this point you may figure out another concern. If the number B of bombs to place is larger than the available positions on the board WxH, then you wont be able to place the bombs on the board. You'll have to check for that restriction when requesting the values for W, H and B.
Then in order to create the array with the number of bombs next to each position, you'll need some way to check for all the neighbouring positions to a given one. If the position is in the middle of the board it has 8 neighbour positions, if it's on an edge it has 5, and if it's on a corner it has 3. Having a helper function return all the valid neighbour positions can be handy.
IEnumerable<(int X, int Y)> NeighbourPositions(int x, int y, int W, int H)
{
bool leftEdge = x == 0;
bool topEdge = y == 0;
bool rightEdge = x == W - 1;
bool bottomEdge = y == H - 1;
if (!leftEdge && !topEdge)
yield return (x-1, y-1);
if (!topEdge)
yield return (x, y-1);
if (!rightEdge && !topEdge)
yield return (x+1, y-1);
if (!leftEdge)
yield return (x-1, y);
if (!rightEdge)
yield return (x+1, y);
if (!leftEdge && !bottomEdge)
yield return (x-1, y+1);
if (!bottomEdge)
yield return (x, y+1);
if (!rightEdge && !bottomEdge)
yield return (x+1, y+1)
}
This function uses Iterators and touples. If you feel those concepts are too complex as you said are new to C#, you can make the function return a list with coordinates instead.
Now the only thing left is to iterate over the whole intArray and increment the value on each position for each neighbour bomb you find.
for (int x = 0; x < W; x++)
{
for (int y = 0; y < H; y++)
{
foreach (var n in NeighbourPositions(x, y, W, H))
{
if (HasBomb(charArray, n.X, n.Y))
intArray[x,y]++;
}
}
}
The answers here are mostly about generating random x and random y put in loop and trying to put the mine into empty cells. It is ok solution, but if you think of it, it is not that sufficient. Every time you try to find a new random cell, there is chance that cell is already a mine. This is pretty much alright, if you don't put too many mines into your field, but if you put some greater number of mines, this event can occur quite often. This means that the loop might take longer than usually. Or, theoretically, if you wanted to put 999 mines into 1000 cell field, it would be really hard for the loop to fill all the necessary cells, especially for the last mine. Now, I am not saying that the solutions here are bad, I think, it's really alright solution for many people. But if someone wanted a little bit efficient solution, I have tried to crate it.
Solution
In this solution, you iterate each cell and try to calculate a probability of the mine to be placed there. I have come up with this easy formula, which calculates the probability:
Every time you try to place a mine into one cell, you calculate this formula and compare it to random generated number.
bool isMine = random.NextDouble() < calcProbability();

Point-wise Multiply Column Array and Matrix using Math.Net Numerics with C#

I want to perform a point-wise multiplication of a column array with each column array/vector in a given Matrix in C# using the Math.Net Numerics library.
There is little documentation on operations like this, so far I have the code below which doesn't work. I am trying to use LINQ as I prefer that over for loops. the problem I'm having with LINQ is I can't reassign my matrix when I try to enumerate each column of my matrix as a vector and do the PointwiseMultiply() method.
Matrix fitKernel is my matrix, and I want to point-wise multiply each column by the wF column array and update my matrix fitKernel using LINQ. fitKernel is 9 x 5 Matrix, and wF is a 9 x 1 double[] array that I convert to a Vector in the LINQ below.
Matrix<double> fitKernel = Matrix<double>.Build.DenseOfColumnArrays(c1, c2, c3, c4, ones);
double[] wF = Enumerable.Repeat(1.0, 9).ToArray();
fitKernel = fitKernel.EnumerateColumns()
.Select(v => v.PointwiseMultiply(Vector<double>.Build.DenseOfArray(wF)));
The above code using the EnumerateColumns() returns an IEnumerable of vectors, but when I try to assign the value to fitKernel it complains about assigning a type of Enumerable to a Matrix.
If you are going to write a for loop, you might as well write two.
// a = double[9];
// c = Matrix<double>
for (int ic = 0; ic < c.ColumnCount; ic++)
{
for (int ir = 0; ir < c.RowCount; ir++) c[ir, ic] = a[ir] * c[ir, ic];
}
It's probably the quickest and briefest solution, but I understand it doesn't tell the reader what you have in mind. OTOH, if you going to use an enumerator, it makes sense to let it control the loop.
var va = Vector<double>.Build.DenseOfArray(a);
var ColEnum = c.EnumerateColumnsIndexed() ;
foreach (System.Tuple<int,Vector<double>> col in ColEnum)
{
Vector<double> v = (Vector<double>)col.Item2.PointwiseMultiply((Vector<double>)va);
c.SetColumn(col.Item1, v);
}
The closest I could get to your first formulation is this:
var r = c.EnumerateColumns().Select(v => v.PointwiseMultiply(va));
int i = 0;
foreach (Vector ri in r) c.SetColumn(i++, ri);
The first line returns your new columns, but you still have to insert them into your Matrix. Note that we are trusting the enumerator to bring back the columns in their natural order. It's possible to reduce this to two lines using EnumerateColumnsIndexed. It requires more detail, but eliminates possible ambiguity about column order.
By the way, it does not work to combine the PointwiseMultiply and the SetColumn in one statement like this:
var r = c.EnumerateColumnsIndexed().Select((v) => c.SetColumn(v.Item1, v.Item2.PointwiseMultiply(va)));
apparently because SetColumn is void. If anyone has a workaround, please post it.
I think I figured it out but you have to use a for loop; doesn't seem to be any easy way using LINQ:
for (int i = 0; i < fitKernel.ColumnCount; i++)
{
var v = fitKernel.Column(i);
v = v.PointwiseMultiply(Vector<double>.Build.DenseOfArray(wF));
fitKernel.SetColumn(i, v);
}

Alternatives to nested Select in Linq

Working on a clustering project, I stumbled upon this, and I'm trying to figure out if there's a better solution than the one I've come up with.
PROBLEM : Given a List<Point> Points of points in R^n ( you can think at every Point as a double array fo dimension n), a double minDistance and a distance Func<Point,Point,double> dist , write a LINQ expression that returns, for each point, the set of other points in the list that are closer to him than minDistance according to dist.
My solution is the following:
var lst = Points.Select(
x => Points.Where(z => dist(x, z) < minDistance)
.ToList() )
.ToList();
So, after noticing that
Using LINQ is probably not the best idea, because you get to calculate every distance twice
The problem doesn't have much practical use
My code, even if bad looking, works
I have the following questions:
Is it possible to translate my code in query expression? and if so, how?
Is there a better way to solve this in dot notation?
The problem definition, that you want "for each point, the set of other points" makes it impossible to solve without the inner query - you could just disguise it in clever manner. If you could change your data storage policy, and don't stick to LINQ then, in general, there are many approaches to Nearest Neighbour Search problem. You could for example hold the points sorted according to their values on one axis, which can speed-up the queries for neighbours by eliminating early some candidates without full distance calculation. Here is the paper with this approach: Flexible Metric Nearest Neighbor Classification.
Because Points is a List you can take advantage of the fact that you can access each item by its index. So you can avoid comparing each item twice with something like this:
var lst =
from i in Enumerable.Range(0, Points.Length)
from j in Enumerable.Range(i + 1, Points.Length - i - 1)
where dist(Points[i], Points[j]) < minDistance
select new
{
x = Points[i], y = Points[j]
};
This will return a set composed of all points within minDistance of each other, but not exactly what the result you wanted. If you want to turn it into some kind of Lookup so you can see which points are close to a given point you can do this:
var lst =
(from i in Enumerable.Range(0, Points.Length)
from j in Enumerable.Range(i + 1, Points.Length - i - 1)
where dist(Points[i], Points[j]) < minDistance
select new { x = Points[i], y = Points[j] })
.SelectMany(pair => new[] { pair, { x = pair.y, y = pair.x })
.ToLookup(pair => pair.x, pair => pair.y);
I think you could add some bool Property to your Point class to mark it's has been browsed to prevent twice calling to dist, something like this:
public class Point {
//....
public bool IsBrowsed {get;set;}
}
var lst = Points.Select(
x => {
var list = Points.Where(z =>!z.IsBrowsed&&dist(x, z) < minDistance).ToList();
x.IsBrowsed = true;
return list;
})
.ToList();

Multidimensional array, elements accessed by vector

Is there any multidimensional array/collection/whatever datatype in .Net, elements of which can be accessed by vector (to vary number of dimensions easily)? Like this (C#):
var array = new Smth<double>(capacity: new int[] {xCap, yCap, zCap});
array[new int[] {x, y, z}] = 10.0;
To clarify: there is no need to explain how can I write such datatype manually.
Upodate:
I mean varying before creation, not after.
// 3D array
var array = new Smth<double>(capacity: new int[] {xCap, yCap, zCap});
array[new int[] {x, y, z}] = 10.0;
// 6D array
var array = new Smth<double>(capacity: new int[] {xCap, yCap, zCap, tCap, vCap, mCap});
array[new int[] {x, y, z, t, v, m}] = 10.0;
Although there are no off-the-shelf collections like that, you can easily emulate them using a Dictionary<int[],double> and a custom IEqualityComparerer<int[]>, like this:
class ArrayEq : IEqualityComparerer<int[]> {
public bool Equals(int[] a, int[] b) {
return a.SequenceEquals(b);
}
public int GetHashCode(int[] a) {
return a.Aggregate(0, (p, v) => 31*p + v);
}
}
With this equality comparer in hand, you can do this:
// The number of dimensions does not matter: if you pass a different number
// of dimensions, nothing bad is going to happen.
IDictionary<int[],double> array = new Dictionary<int[],double>(new ArrayEq());
array[new[] {1,2,3}] = 4.567;
array[new[] {1,2,-3}] = 7.654; // Negative indexes are OK
double x = array[new[] {1,2,3}]; // Get 4.567 back
If you need to have a certain capacity and a specific number of dimensions, you can modify the ArrayEq to be more strict at validating the data.
If you knew the number of dimensions at compile-time, you could use one of the Tuple<...> classes instead of arrays for potentially better performance. You could also define extension methods on multi-dimensional, say, double[,,,], arrays, to take vectors of indexes. Neither of these two approaches offers the same flexibility, though (which is a common trade-off -- better performance can often be gained by reducing flexibility).
EDIT: If you need to pre-allocate the storage and avoid storing your indexes, you could implement a multi-dimensional array yourself - like this:
class MultiD<T> {
private readonly T[] data;
private readonly int[] mul;
public MultiD(int[] dim) {
// Add some validation here:
// - Make sure dim has at least one dimension
// - Make sure that all dim's elements are positive
var size = dim.Aggregate(1, (p, v) => p * v);
data = new T[size];
mul = new int[dim.Length];
mul[0] = 1;
for (int i = 1; i < mul.Length; i++) {
mul[i] = mul[i - 1] * dim[i - 1];
}
}
private int GetIndex(IEnumerable<int> ind) {
return ind.Zip(mul, (a, b) => a*b).Sum();
}
public T this[int[] index] {
get { return data[GetIndex(index)]; }
set { data[GetIndex(index)] = value; }
}
}
This is a straightforward implementation of row-major indexing scheme that uses generics.

Linq to find pair of points with longest length?

I have the following code:
foreach (Tuple<Point, Point> pair in pointsCollection)
{
var points = new List<Point>()
{
pair.Value1,
pair.Value2
};
}
Within this foreach, I would like to be able to determine which pair of points has the most significant length between the coordinates for each point within the pair.
So, let's say that points are made up of the following pairs:
(1) var points = new List<Point>()
{
new Point(0,100),
new Point(100,100)
};
(2) var points = new List<Point>()
{
new Point(150,100),
new Point(200,100)
};
So I have two sets of pairs, mentioned above. They both will plot a horizontal line. I am interested in knowing what the best approach would be to find the pair of points that have the greatest distance between, them, whether it is vertically or horizontally. In the two examples above, the first pair of points has a difference of 100 between the X coordinate, so that would be the point with the most significant difference. But if I have a collection of pairs of points, where some points will plot a vertical line, some points will plot a horizontal line, what would be the best approach for retrieving the pair from the set of points whose difference, again vertically or horizontally, is the greatest among all of the points in the collection?
Thanks!
Chris
Use OrderBy to create an ordering based on your criteria, then select the first one. In this case order by the maximum absolute difference between the horizontal and vertical components in descending order.
EDIT: Actually, I think you should be doing this on the Tuples themselves, right? I'll work on adapting the example to that.
First, let's add an extension for Tuple<Point,Point> to calculate it's length.
public static class TupleExtensions
{
public static double Length( this Tuple<Point,Point> tuple )
{
var first = tuple.Item1;
var second = tuple.Item2;
double deltaX = first.X - second.X;
double deltaY = first.y - second.Y;
return Math.Sqrt( deltaX * deltaX + deltaY * deltaY );
}
}
Now we can order the tuples by their length
var max = pointCollection.OrderByDescending( t => t.Length() )
.FirstOrDefault();
Note: it is faster to just iterate over the collection and keep track of the maximum rather than sorting/selecting with LINQ.
Tuple<Point,Point> max = null;
foreach (var tuple in pointCollection)
{
if (max == null || tuple.Length() > max.Length())
{
max = tuple;
}
}
Obviously, this could be refactored to an IEnumerable extension if you used it in more than one place.
You'll need a function probably using the pythagorean theorem to calculate the distances
a^2 + b^2 = c^2
Where a would be the difference in Point.X, b would be the difference in Point.Y, and c would be your distance. And once that function has been written, then you can go to LINQ and order on the results.
Here's what I did. (Note: I do not have C# 4, so it's not apples to apples
private double GetDistance(Point a, Point b)
{
return Math.Pow(Math.Pow(Math.Abs(a.X - b.X), 2) + Math.Pow(Math.Abs(a.Y - b.Y), 2), 0.5);
}
You can turn that into an anonymous method or Func if you prefer, obviously.
var query = pointlistCollection.OrderByDescending(pair => GetDistance(pair[0], pair[1])).First();
Where pointlistCollection is a List<List<Point>>, each inner list having two items. Quick example, but it works.
List<List<Point>> pointlistCollection
= new List<List<Point>>()
{
new List<Point>() { new Point(0,0), new Point(3,4)},
new List<Point>() { new Point(5,5), new Point (3,7)}
};
***Here is my GetDistance function in Func form.
Func<Point, Point, double> getDistance
= (a, b)
=> Math.Pow(Math.Pow(Math.Abs(a.X - b.X), 2) + Math.Pow(Math.Abs(a.Y - b.Y), 2), 0.5);
var query = pointlistCollection.OrderByDescending(pair => getDistance(pair[0], pair[1])).First();
As commented above: Don't sort the list in order to get a maximum.
public static double Norm(Point x, Point y)
{
return Math.Sqrt(Math.Pow(x.X - y.X, 2) + Math.Pow(x.Y - y.Y, 2));
}
Max() needs only O(n) instead of O(n*log n)
pointsCollection.Max(t => Norm(t.Item1, t.Item2));
tvanfosson's answer is good, however I would like to suggest a slight improvement : you don't actually need to sort the collection to find the max, you just have to enumerate the collection and keep track of the maximum value. Since it's a very common scenario, I wrote an extension method to handle it :
public static class EnumerableExtensions
{
public static T WithMax<T, TValue>(this IEnumerable<T> source, Func<T, TValue> selector)
{
var max = default(TValue);
var withMax = default(T);
bool first = true;
foreach (var item in source)
{
var value = selector(item);
int compare = Comparer<TValue>.Default.Compare(value, max);
if (compare > 0 || first)
{
max = value;
withMax = item;
}
first = false;
}
return withMax;
}
}
You can then do something like that :
Tuple<Point, Point> max = pointCollection.WithMax(t => t.Length());

Categories