Getting all the possible distances between points - c#

I have created a program to spawn a number of points (the number is given by the user).
Therefore the program spawns N points
see the image for an example, it has 3 points in that case
What I need is to get all the possible distances between those villages (In the example it's distance: AB, AC, BC).
The points are stored in a single array (that scores x-coordinate and y-coordinate)
List<Villages>
I know that I new Pythagoras Theorem, I just cannot get the foreach loop right.

I would think you would want a regular nested for-loop rather than foreach.
Something like this should work:
for (int i = 0; i < villageList.Count; ++i)
{
for (int j = i + 1; j < villageList.Count; ++j)
{
distanceFunc(villageList[i], villagelist[j]);
}
}
Where distanceFunc is whatever implementation of a distance function you want to use and villageList is your List of villages.
The reason you would use for-loops is because you need the inner loop to start one element past the the outer loop (i + 1), and foreach loops don't let you easily access the index you're currently at (they let you access the element itself, but not easily see it's position in the array).

You need two for loops:
var villages = new List<Villages>() { ... };
for (int i = 0; i < villages.Count - 1; i++)
for (int j = i + 1; j < villages.Count; j++)
Console.WriteLine(getDistance(villages[i], villages[j]));
Where getDistance you should write yourself. It should return a distance between two specified Villages.

How about something like this pseudocode:
villages = [a, b, c, ...]
for i=0 to len(villages)-2:
for j=i+1 to len(villages)-1:
print(villages[i], villages[j], dist(villages[i], villages[j]))

Related

How to determine groups of interconnected nodes in a two-dimensional array (graph)?

I have a program that compares objects by their properties and then converts it all in a two dimensional array (or a matrix) with values being percentages (1 means 100% similar, 0 means completely different, anything in between is % of similarity).
After that I convert all of it to 1's and 0's to create a map of connections or what's called an adjacency matrix in graph theory which represents nodes that are connected to one another.
Here's what my situation looks like in terms of graph/matrix/array
It's clear from the image that there are 4 distinct groups of elements: a1 through a5 are all linked together and form first group, b1-b2-b3 form another group of elements, b4 and b6 are a third group of just two elements and b5 forms it's own fourth group because it isn't connected to anybody else.
I have the same array in my code. My question is how can I determine which elements belong to the same group or how to group them and store the information about them somewhere else? (be it the index of the element, the value or something else).
I also need to make sure that I don't have repeating groups, so for example elements b4 and b6 shouldn't form group b4-b6 and group b6-b4, only one of those groups should be present.
Here's part of my code where I tried to implement it by creating new array of strings (and I tried integer too, but it couldn't store the index [0,0] properly, it just stores 0), but this method still doesn't solve the issue of repeating groups or how to identify and pull them out of this array. This method can only correctly identify connections. Output of this method
public static string[,] CreateConnectionsMap(double[,] arr)
{
string[,] newArr = new string[arr.GetLength(0), arr.GetLength(1)];
for (int i = 0; i < arr.GetLength(0); i++)
{
for (int j = 0; j < arr.GetLength(1); j++)
{
if (arr[i, j] != 0 && arr[i, j] == arr[j, i])
{
newArr[i, j] = $"{i}|{j}";
}
else newArr[i, j] = "0";
}
}
return newArr;
}
Seems to me that you're trying to do clustering using a pairwise distance.
The most immediate solution that comes to my mind is to use the agglomerative clustering algorithm.
This library in c# should do the job.
Try something like this:
public static int[] CreateConnectionsMap(double[,] arr)
{
if (arr.GetLength(0) != arr.GetLength(1))
throw new ArgumentException("Matrix must be square.");
int[] groups = new int[arr.GetLength(0)];
for (int i = 0; i < arr.GetLength(0); i++)
{
groups[i] = i;
for (int j = 0; j < i; j++)
{
if (arr[i, j] != 0 && arr[i, j] == arr[j, i])
{
groups[i] = groups[j];
break;
}
}
}
return groups;
}
Be sure to test it!
You need to discover the maximal cliques in the graph.
copy graph to work
set flag true
while flag == true
clear current clique
while work contains nodes
if current clique empty
move arbitrary node from work to current clique
else
set flag false
LOOP w over nodes in work
LOOP c over nodes in current clique
if w connected to c
move w to current clique
set flag true
if flag == false
break
add current clique to list of cliques
Here is c++ code implementing this algorithm https://github.com/JamesBremner/PathFinder2/blob/dbd6ff06edabd6a6d35d5eb10ed7972dc2d779a6/src/cPathFinder.cpp#L483

What sorting method is this being applied and what is the algorithmic complexity of the method

I came across the code below for implementing sorting array.
I have applied to a very long array and it was able to do so in under a sec may be 20 millisec or less.
I have been reading about Algorithm complexity and the Big O notation and would like to know:
Which is the sorting method (of the existing ones) that is implemented in this code.
What is the complexity of the algorithm used here.
If you were to improve the algorithm/ code below what would you alter.
using System;
using System.Text;
//This program sorts an array
public class SortArray
{
static void Main(String []args)
{
// declaring and initializing the array
//int[] arr = new int[] {3,1,4,5,7,2,6,1, 9,11, 7, 2,5,8,4};
int[] arr = new int[] {489,491,493,495,497,529,531,533,535,369,507,509,511,513,515,203,205,207,209,211,213,107,109,111,113,115,117,11913,415,417,419,421,423,425,427,15,17,19,21,4,517,519,521,523,525,527,4,39,441,443,445,447,449,451,453,455,457,459,461,537,539,541,543,545,547,1,3,5,7,9,11,13,463,465,467,23,399,401,403,405,407,409,411,499,501,503,505,333,335,337,339,341,343,345,347,65,67,69,71,73,75,77,79,81,83,85,87,89,91,93,95,9,171,173,175,177,179,181,183,185,187,269,271,273,275,277,279,281,283,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63,133,135,137,139,141,143,145,285,287,289,291,121,123,125,127,129,131,297,299,373,375,377,379,381,383,385,387,389,97,99,101,103,105,147,149,151,153,155,157,159,161,163,165,167,16,391,393,395,397,399,401,403,189,191,193,195,197,199,201,247,249,251,253,255,257,259,261,263,265,267,343,345,347,349,501,503,505,333,335,337,339,341,417,419,421,423,425,561,563,565,567,569,571,573,587,589,591,593,595,597,599,427,429,431,433,301,303,305,307,309,311,313,315,317,319,321,323,325,327,329,331,371,359,361,363,365,367,369,507,509,511,513,515,351,353,355,57,517,519,521,523,525,527,413,415,405,407,409,411,499,435,437,469,471,473,475,477,479,481,483,485,487,545,547,549,551,553,555,575,577,579,581,583,585,557,559,489,491,493,495,497,529,531,533,535,537,539,541,543,215,217,219,221,223,225,227,229,231,233,235,237,239,241,243,245,293,295};
int temp;
// traverse 0 to array length
for (int i = 0; i < arr.Length ; i++)
{
// traverse i+1 to array length
//for (int j = i + 1; j < arr.Length; j++)
for (int j = i+1; j < arr.Length; j++)
{
// compare array element with
// all next element
if (arr[i] > arr[j]) {
///Console.WriteLine(i+"i before"+arr[i]);
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
//Console.WriteLine("i After"+arr[i]);
}
}
}
// print all element of array
foreach(int value in arr)
{
Console.Write(value + " ");
}
}
}
This is selection sort. It's time complexity is O(𝑛²). It has nested loops over i and j, and you can see these produce every possible set of two indices in the range {0,...,𝑛-1}, where 𝑛 is arr.Length. The number of pairs is a triangular number, and is equal to:
𝑛(𝑛-1)/2
...which is O(𝑛²)
If we stick to selection sort, we can still find some improvements.
We can see that the role of the outer loop is to store in arr[i] the value that belongs there in the final sorted array, and never touch that entry again. It does so by searching the minimum value in the right part of the array that starts at this index 𝑖.
Now during that search, which takes place in the inner loop, it keeps swapping lesser values into arr[i]. This may happen a few times, as it might find even lesser values as j walks to the right. That is a waste of operations, as we would prefer to only perform one swap. And this is possible: instead of swapping immediately, delay this operation. Instead keep track of where the minimum value is located (initially at i, but this may become some j index). Only when the inner loop completes, perform the swap.
There is less important improvement: i does not have to get equal to arr.Length - 1, as then there are no iterations of the inner loop. So the ending condition for the outer loop can exclude that iteration from happening.
Here is how that looks:
for (int i = 0, last = arr.Length - 1; i < last; i++)
{
int k = i; // index that has the least value in the range arr[i..n-1] so far
for (int j = i+1; j < arr.Length; j++)
{
if (arr[k] > arr[j]) {
k = j; // don't swap yet -- just track where the minimum is located
}
}
if (k > i) { // now perform the swap
int temp = arr[i];
arr[i] = arr[k];
arr[k] = temp;
}
}
A further improvement can be to use the inner loop to not only locate the minimum value, but also the maximum value, and to move the found maximum to the right end of the array. This way both ends of the array get sorted gradually, and the inner loop will shorten twice as fast. Still, the number of comparisons remains the same, and the average number of swaps as well. So the gain is only in the iteration overhead.
This is "Bubble sort" with O(n^2). You can use "Mergesort" or "Quicksort" to improve your algorithm to O(n*log(n)). If you always know the minimum and maximum of your numbers, you can use "Digit sort" or "Radix Sort" with O(n)
See: Sorting alrogithms in c#

Can't figure out infinite loop

I have a list of potential sites to place landing pads in a 2d array. They're kept in 2 ints, one for row and one for column. I need to Randomly add a few landing sites from this list but for some reason it more often than not uses the same spots. I'd like to exclude these spots somehow so I used this loop but it locks up into an infinite loop for some reason and I just can't figure out why!
for(int j = 0; j < amountLandingPads; j++)
{
int r = Random.Range(0,potSitesC.Length-1);
while(roomType[potSitesR[r],potSitesC[r]] == (int)room.Landing)
{
r = Random.Range(0,potSitesC.Length-1);
}
roomType[potSitesR[r],potSitesC[r]] = (int)room.Landing;
//do more stuff
}
To me it looks like if the current site is already designated as a landing site, randomly choose another until you find a site that isn't a landing pad, what am I doing wrong?
potSites.Length is always gonna be 20+ and ammountLandingPads is always potsites.Length/4 and minimum 1.
roomtype is the type of room at that position (in a 2d int array)
It looks like you're using the same int r and also potSitesR.Length to decide both the row-coord and the column-coord of the landing site. This will end up always selecting positions from both potSitesR and potSitesC with the same indices, i.e. (potSitesR[1], potSitesC[1]), or (potSitesR[2], potSitesC[2]), and so on... and always within the potSitesR.Length range.
Try using a different value for both for more randomization. Here's example code:
for(int j = 0; j < amountLandingPads; j++)
{
//In the following statement
//Removed -1 because int version is exclusive of second parameter
//Changed it to potSitesR.Length (from potSitesC.Length)
int r = Random.Range(0, potSitesR.Length);
//second randomized number for column-randomization.
int c = Random.Range(0, potSitesC.Length);
while (roomType[potSitesR[r],potSitesC[c]] == (int)room.Landing) //using both randomized numbers
{
r = Random.Range(0, potSitesR.Length); // r from potSitesR.Length
c = Random.Range(0, potSitesC.Length); // c from potSitesC.Length
}
roomType[potSitesR[r], potSitesC[c]] = (int)room.Landing;
//do more stuff
}
I hope that helps!

How does `foreach` iterate through a 2D array?

I was curious as to how a foreach loop in C# iterates over a multidimensional array. In the following code, the second nested for loop was originally a foreach which would give the incorrect position of the pitches placed in the loop. I know it's kind of difficult to intuit what it does, but it's basically this: Pitches are put into a multidimensional array (here, numVoices is 2 and exLength is 10) so that you will have a 2x10 array of pitches; each of these rows of pitches are then played at the same time by the MIDI output device. When I used a foreach to then put the pitches' names into a string so that I could display what pitches were in what place inside of the grid, the foreach would display them in the "wrong" order (i.e., [0,3] in the pitch grid was not what was printed in the string). Using a nested for, this problem disappeared. I tried to recreate this with a smaller example of a 2D list of ints (code below) but it gives the "right" answer this time. Why?
//put pitches into grid
//numVoices = 2, exLength = 10 (10 notes long, 2 voices)
for (int i = 0; i < numVoices; i++ )
{
for(int j = 0; j < exLength; j++)
{
//here we generate random pitches in different octaves
//depending on the voice (voice 2 is in octave
//below voice 1, etc)
randnum = (random.Next(100 - (i * 13), 112 - (i * 13)));
melodyGrid[j, i] = (Pitch)randnum;
}
}
for (int i = 0; i < numVoices; i++)
{
for (int j = 0; j < exLength; j++)
{
//this down here makes it more readable for
//humans
//e.g. "FSharp5" becomes "F#5"
noteNames += String.Format("{0, -6}", melodyGrid[j,i].ToString().Replace("Sharp", "#").Replace("Flat", "b"));
}
noteNames += "\r\n"; //lower voices are just separated by newlines
}
Console.WriteLine(noteNames);
The following code works "correctly," however:
int[,] nums = { {1, 2, 3},
{4, 5, 6},
{7, 8 ,9} };
foreach (int i in nums)
{
Console.Write("{0} ", i);
}
Is it possible I was just making a semantic mistake? Or do foreach loops iterate through arrays in differing manners?
I was curious as to how a foreach loop in C# iterates over a multidimensional array.
As always for questions like this, the ultimate authority is the C# language specification. In this case, section 8.8.4:
The order in which foreach traverses the elements of an array, is as follows: For single-dimensional arrays elements are traversed in increasing index order, starting with index 0 and ending with index Length – 1. For multi-dimensional arrays, elements are traversed such that the indices of the rightmost dimension are increased first, then the next left dimension, and so on to the left.
Now, compare that with how you're iterating with your for statements:
for (int i = 0; i < numVoices; i++ )
{
for(int j = 0; j < exLength; j++)
{
...
melodyGrid[j, i] = (Pitch)randnum;
In other words, you're incrementing the leftmost dimension first... so yes, this will give a different result from foreach. If you want to use foreach but get the same iteration order, you'll need to switch the indexes for voices and length. Alternatively, if you want to keep the same order of indexes, just use the for loop and be happy with it.

Modify items in List<T> fast

I tried to make this code perform faster using Parallel.ForEach and ConcurrentBag but it's still running way to long (esp. when having in mind that in my scenario i may also be 1.000.000++):
List<Point> points = new List<Point>();
for(int i = 0; i<100000;i++) {
Point point = new Point {X = i-50000, Y = i+50000, CanDelete = false};
points.Add(point);
}
foreach (Point point in points) {
foreach (Point innerPoint in points) {
if (innerPoint.CanDelete == false && (point.X - innerPoint.X) < 2) {
innerPoint.Y = point.Y;
point.CanDelete = true;
}
}
}
That code will perform WORSE in parallel, due to the data access patterns.
The best way to speed it up is to recognize that you don't need to consider all O(N^2) pairs of points, but only the ones having nearby X-coordinates.
First, sort the list by X-coordinate, O(N log N), then process forward and backward in the list from each point until you leave the neighborhood. You'll need to use indexing and not foreach.
If your sample data, the list is already sorted.
Since your distance test is symmetric, and removes matching points from consideration, you can skip looking at earlier points.
for (int j = 0; j < points.Length; ++j) {
int x1 = points[j].X;
//for (int k = j; k >= 0 && points[k].X > x1 - 2; --k ) { /* merge points */ }
for (int k = j + 1; k < points.Length && points[k].X < x1 + 2; ++k ) { /* merge points */ }
}
Not only is the complexity better, the cache behavior is far superior. And it can be split among multiple threads with far less cache contention.
Well, I don't know exactly what do you want, but let's try.
First, when creating the List, you might want to set it's desired initial size, since you know how many items it will hold. So it does not need to grow all the time.
List<Point> points = new List<Point>(100000);
Next, you could sort the list by the X property. So you would only compare each point with the points that are near it: when you find the first, forward or backward, that is too distant, you can stop comparing.

Categories

Resources