I am developing a game in Unity, c#.
I have a large Vector3 list of 16k elements that has holds x position, y for dic key and z position.
The list gets sorted very often but only 2750 of that list gets sorted and the rest remains unsorted.
Right now I am using linq for a quickstort with orderby:
list = list.OrderBy(x => x).ToList
But it is not the right sort algorithm for my case.
I have no idea how to implement an Insertion sort for a Cector3 list. Just did it with simple arrays. Is there maybe an Insertion sort (ascending and descending) for Vector3 list already in linq?
Well turns out insertion sort is worse.
Thats how I wrote it:
static void sortVec3Array(Vector3[] arrayToSort, int startAt, int stopAt)
{
int i, j;
for (i = startAt+1; i < stopAt; i++)
{
float item = arrayToSort[i].x;
int ins = 0;
for (j = i - 1; j >= 0 && ins != 1;)
{
if (item < arrayToSort[j].x)
{
arrayToSort[j + 1].x = arrayToSort[j].x;
j--;
arrayToSort[j + 1].x = item;
}
else ins = 1;
}
}
}
Came across Tim Sort which is kinda what I need.
I implemented it and it works like a charm. Ms is like 1.4 - 1.9 which is 3 times faster than the .Orderby algorithm and now useable for me.
Related
I am trying to write code that finds the lowest and highest values stored in an array and then removes them from the array to compute an average.
Currently I have written code to produce the average of all numbers in the array but I need to change that once I figure out how to remove Highest and lowest value.
Code I have:
private void HighAndLow()
{
try
{
int[] HighAndLowGrade;
int[] highest = HighAndLowGrade.Max();
int lowest = HighAndLowGrade.Min();
}
catch
{
MessageBox.Show("HighAndLow Method failed");
}
}
//find average without highest and lowest values
private void ComputeMean()
{
double total = 0;
for (int index = 2; index < 9; index ++)
{
total += double.Parse(lineContent[index]);
}
averageTestScore = total / 7;
}
This should work from what I have tested so far.
int[] numberArray = new int[] {1,2,5,9,5,2};
double answer = 0;
var ignoreList = new List<decimal>() {
numberArray.Max(),
numberArray.Min()
};
var cleanList = numberArray.Where(x => !ignoreList.Contains(x));
answer = cleanList.Any() ? cleanList.Average() : 0;
This only requires one iteration through the collection:
public double ComputeAdjustedMean(IEnumerable<int> items)
{
int total = 0;
int count = 0;
int min = int.MaxValue;
int max = int.MinValue;
foreach(int item in items)
{
count++;
total += item;
if (item < min) min = item;
if (item > max) max = item;
}
if (count <= 2) // not enough items
{
// do something here
}
return (total - (min + max)) / (double)(count - 2);
}
Try this using bubble sorting algorithm-
static void Main(string[] args)
{
int[] array = { 12, 6, 34, 23, 89 };
int temp;
for (int i = 0; i <= array.Length - 2; i++)
{
if (array[i] > array[i + 1])
{
temp = array[i];
array[i] = array[i + 1];
array[i + 1] = temp;
}
}
array = array.Skip(1).SkipLast(1).ToArray();
Console.WriteLine((array.Sum()) / (array.Length));
Console.Read();
}
If you have an array of values then you can do this neat LINQ query:
var average_skip_min_and_max =
values
.OrderBy(x => x)
.Skip(1)
.Take(values.Length - 2)
.Average();
I really don't get people when they encounter this kind of questions, they became insanely eager to provide a direct answer. This question is obviously a homework assignment. I'm not saying we don't help OPs but we need to lead them to solutions.
Dear OP,
Do not use the LINQ, yet. I think your instructor is meaning you to learn the sorting algorithms and memory operations. Do some research about them, say, Buble Sort, to sort the array you have. Then it'll be in front of you how to implement and use. After then, you should use the framework provided methods like LINQ's Min() / Max() extension methods.
The approach to your problem is could be like this:
Sort the array ascending.
Get the first element which is now the minimum valued element.
Reallocate a new array but 1 element shorter
Copy your entire array with the current ordered state to newly allocated array but skip the first element when copying, start with next element.
Get the minimum again, but this time search in the newly allocated array and check with the previous minimum
If they are equal go the 3rd operation, if you need to eliminate the repeating minimums ( [1, 1, 2, 3 ...] ), which I think you need to.
If they are not equal, then it means you've found the minimum element of your array and removed all occurences
Now if you repeat the approach to finding the maximum valued element you are done with the elimination process.
I am attempting to create an adjacency matrix from a 2D array of nodes. The adjacency matrix will be passed to a program that will cluster the nodes either through
Spectral clustering algorithm
Kmeans clustering algorithm
**Node class **
public class Node{
public int _id;
public bool _isWalkable;
public int _positionX;
public int _positionY;
public Vector3 _worldPosition;
}
Grid Class
public class Grid : MonoBehaviour
{
void CreateGrid()
{
grid = new Node[_gridSizeX, _gridSizeY];
Vector3 worldBottomLeft = transform.position -
Vector3.right * worldSize.x / 2 - Vector3.forward * worldSize.y / 2;
//set the grid
int id = 0;
for (int x = 0; x < _gridSizeX; x++)
{
for (int y = 0; y < _gridSizeY; y++)
{
Vector3 worldPosition = worldBottomLeft + Vector3.right *
(x * _nodeDiameter + _nodeRadius) +
Vector3.forward * (y * _nodeDiameter + _nodeRadius);
//check to see if current position is walkable
bool isWalkable =
!Physics.CheckSphere(worldPosition, _nodeRadius, UnwalkableMask);
grid[x, y] = new Node(isWalkable, worldPosition, x, y);
grid[x, y].Id = id ++;
}
}
totalNodes = id;
}
}
Nodes are stored inside a 2D array called grid and represent a walkable path for a character to move on. I have succesfully implemented an A* algorithm with a euclidean distance heuristic. What I would like to do is cluster these nodes using the aforementioned clustering algorithms, but first I need to create an adjacency algorithm for them. This is the best pseudocode I could come up with
int[][] _adjacencyMatrix = new int[gridSizeX*gridSizeY][gridSizeX*gridSizeY];
for(int x = 0; x < gridSize;x< XgridSize; i++)
{
for(int y = 0; y < gridSize;y< YgridSize; i++)
{
if( !Grid[x][y]._isWalkable)
continue;
Node n = Grid[x][y];
List<Node> neighbors = GetNeighbors(n);
for(int k; k<neighbors.Count(); k++)
{
_adjacencyMatrix[n._id][neighbors[k]._id]=1;
}
}
}
public List<Node> GetNeighbours(Node n)
{
//where is this node in the grid?
List<Node> neighbours = new List<Node>();
//this will search in a 3X3 block
for (int x = -1; x <= 1; x++)
{
for (int y = -1; y <= 1; y++)
{
if (x == 0 && y == 0)
continue; //we're at the current node
int checkX = n._positionX + x;
int checkY = n._positionY + y;
if (checkX >= 0 && checkX < _gridSizeX && checkY >= 0
&& checkY < _gridSizeY)
{
if(grid[checkX, checkY]._isWalkable)
neighbours.Add(grid[checkX, checkY]);
else
continue;
}
}
}
return neighbours;
}
My main concern
My main concern with this is the total complexity of the above algorithm. It feels like it's going to be heavy and I have a total of (75^2 = 5625) nodes in a adjacency matrix that will be 5625X5625 in size! There must be a better way to find the neighbors than this, is there?
The matrix is symmetric, so you only need to save half of it, see (How to store a symmetric matrix?) for an example. The matrix values are binary, so saving them as booleans or in a bit vector will cut down memory by a factor of 4 or 32, respectively.
Alternatively, since the check for two adjacent nodes takes constant time (abs(n1.x - n2.x) <= 1 && abs(n1.y - n1.y) <= 1 && grid[n1.x, n2.x].isWalkable() && grid[n2.x, n2.y]), you could just pass the clustering algorithm a function which checks for adjacency on-the-fly.
5k by 5k is not very large. 100 MB is something you can keep in memory. If you want to avoid this cost, do not use algorithms based on distance matrixes!
However, since your similarity appears to be
d(x,y) = 1 if adjacent and both nodes walkable else 0
your results will degenerate. If you are lucky, you get something like connected components (which you could have gotten much easier).
Pairwise shortest paths would be more useful, but also more expensive to build. Maybe consider solving this first, though. Having a full adjacency matrix is a good starting point I guess.
k-means cannot work with pairwise distances at all. It needs distances point-to-mean only, for arbitrary means.
I suggest to look at graph algorithms, and spend some more time understanding your objective, before trying to squeeze the data into clustering algorithms that may be solving a different problem.
I'm having another problem in my Bejeweled clone. I want to make Star Gems act like they do in Bejeweled 3, meaning they destroy gems outward from the star gem(the center). So, say the star gem was at (4, 4) in a 10x10 2D array; it would destroy the positions (3, 4), (5, 4), (4, 3) and (4, 5) first, then, say, 10 frames later, destroy (2, 4), (6, 4), (4, 2), and (4, 6), and so on.
Right now I have the StarDestruction() method storing the position of the star gem to a couple of Board-scope variables, and the positions to destroy in a List<Gem>, like so:
Board.starPosX = i;
Board.starPosY = j;
for (int x = 0; x < gems.GetLength(0); x++)
{
moveTimer = 0;
int k = x;
int m = x;
int q = x;
int n = x;
if (i - k < 0) k = 0;
if (i + m > gems.GetLength(0) - 1) m = 0;
if (j - q < 0) q = 0;
if (j + n > gems.GetLength(1) - 1) n = 0;
gemQ.Add(gems[i - k, j]);
gemQ.Add(gems[i + m, j]);
gemQ.Add(gems[i, j - q]);
gemQ.Add(gems[i, j + n]);
}
where gemQ is the List<Gem> and gems is the 2D Gem array.
This is how I currently destroy the gems, in Update():
foreach (Gem g in gemQ)
{
if (timer2 % 12 == 0)
g.KillGem(gems[starPosX, starPosY]);
}
where timer2 is the timer for destroying the gems.
I have a bit simpler code for the original gem destroying, but it didn't seem to work any differently than this version. Here's the simpler code:
for (int x = 0; x < gems.GetLength(0); x++)
{
if (x != i)
{
gems[x, j].KillGem(gems[i, j]);
}
if (x != j)
{
gems[i, x].KillGem(gems[i, j]);
}
}
Any ideas?
Complete edit of my reply, based on our conversation in the comments.
I understand now that:
You want the star gem to destroy all other gems in the same column and same row as the star gem.
You want four gems to be destroyed at a time, with a delay between each four.
The explosion should move outward from the star gem, i.e. destroying the closest gems first.
Your foreach uses the time like this:
Timer % 12 == 0
At the time that is true for one gem, its true for all of them typically. You don't want to stall between destructions either, otherwise the destruction won't get rendered or the game will visibly lag.
The second issue is that even if you did space out the destruction of the gems, you'll likely find that the destruction occurs in a spiral, instead of four at a time.
With these points in mind, you'll need to do this instead:
// The initial destroy gem code
var gemsToDestroy = new List<Gem>();
for (int x = 0; x < gems.GetLength(0); x++)
{
if (x != i)
{
gemsToDestroy.add(gems[x, j]);
}
if (x != j)
{
gemsToDestroy.add(gems[i, x]);
}
}
// You can change your for loop above to achieve this directly, but this is the idea
// We are putting them in order of closest first.
gemsToDestroy = gemsToDestroy.OrderBy(o => o.DistanceFromStar).ToList();
// Your periodic UPDATE code - This is pseudo code but should convey the general idea
// I've been very lazy with my use of LINQ here, you should refactor this solution to
// to remove as many iterations of the list as possible.
if (gemsToDestroy.Any() && timer.Ready)
{
var closestDistance = gemsToDestroy[0].DistanceFromStar;
foreach (var gem in gemsToDestroy.Where(gem => gem.DistanceFromStar == closestDistance))
{
gem.Destroy();
}
// Again you can do this without LINQ, point is I've removed the now destroyed gems from the list
gemsToDestroy = gemsToDestroy.Where(gem => gem.DistanceFromStar != closestDistance).ToList();
timer.Reset(); // So that we wait X time before destroying the next set
}
Don't forget to prevent player input while there are items in the gemsToDestroy list and also to stop the game timer while destroying, so that the player isn't penalised time for playing well.
I know how binary search works, and also know how Insertion sort works but this code is about Binary Insertion Sort and i have problem in understanding how it works.
static void Main(string[] args)
{
int[] b = BinarySort(new[] { 4, 3, 7, 1, 9, 6, 2 });
foreach (var i in b)
Console.WriteLine(i);
}
public static int[] BinarySort(int[] list)
{
for (int i = 1; i < list.Length; i++)
{
int low = 0;
int high = i - 1;
int temp = list[i];
//Find
while (low <= high)
{
int mid = (low + high) / 2;
if (temp < list[mid])
high = mid - 1;
else
low = mid + 1;
}
//backward shift
for (int j = i - 1; j >= low; j--)
list[j + 1] = list[j];
list[low] = temp;
}
return list;
}
I don't understand what this part do:
//backward shift
for (int j = i - 1; j >= low; j--)
list[j + 1] = list[j];
list[low] = temp;
and what is the purpose of using binary search here?
Can you tell me how binary insertion sort works? (c# console)
code source:http://w3mentor.com/learn/asp-dot-net-c-sharp/asp-dot-net-language-basics/binary-insertion-sort-in-c-net/
Binary insertion sort works as insertion sort, but it separates locating the insertion point from the actual insertion.
Insertion sort implemented for an array will move items at the same time as locating the insertion point. While looping through the items to find the insertion point, it will also shift the items to make room for the insertion.
Binary insertion sort will make use of the fact that the items that are already sorted are sorted, so it can use a binary search to find the insertion point. As the binary search can't also shift the items to make room for the insertion, that has to be done in a separate step after the insertion point has been found.
The code that you wanted explained is the code that shifts the items to make room for the insertion.
I need to create an Array with Linked list capacities.
Basically, I need a static index based list (like array), but with the possibility to get next and previous field (and easily loop back and forward through list, like with linked list).
Note: Array is 2 dimensional. I use a custom class as array values. So I can set previous and next property for each instance.
Is there a built in C# collection for this? If not, any suggestions on how to create a very simple version of this? (I already have a version of this, consisting of 2 methods. One that loops forward to set the previous field, and one to loop backwards that set the next field, but it's still to messy).
Thanks in advance
EDIT:
The problem is my use of 2dimensional array. If loop through my array:
for (byte x = 0; x < Grid.GetLength(0); x++)
{
for (byte y = 0; y < Grid.GetLength(1); y++) /
{
//At certain point, I need to get the previous field. I can do:
if (y != 0)
{
y -= 2; //-2 because I will y++ in for. Already getting messy
}
else
{
//What if y == 0? Then I can't do y--. I should get max y and do x-- to get previous element:
y = (byte)(Grid.GetLength(1) - 1); //to get max value y
x--;
}
}
}
There is a built-in LinkedList<T> class.
But from your description why wouldn't an array work? It's static, and index-based, and you can easily get the next and previous element by incrementing / decrementing the index. It's hard to see exactly what you need from your code, but I'd like to point out that you can easily enumerate over a multi-dimensional array with:
var arry = new int[2,3];
foreach(var item in arry)
{
...
}
So you might be able to combine this with a Stack<T> structure (push items on the stack and pop them off to get the previous).
Alternatively, you can turn the array into a LinkedList directly.
var list = new LinkedList(arry.Cast<int>()); // flattens array
Or to preserve the indexes from the original array and still loop through the values as a linked list use:
var list = new LinkedList(arry.Cast<int>.Select((item, i) => new
{
Item = item,
Index1 = i % arry.GetLength(1),
Index2 = i / arry.GetLength(0)
}));
var node = list.First;
while(node.Next != null)
{
Console.WriteLine("Value # {1}, {2}: {0}", node.Value.Item, node.Value.Index1, node.Value.Index2);
// on some condition move to previous node
if (...)
{
node = node.Previous;
}
else
{
node = node.Next;
}
}
No, you don't. Instead of abandoning traditional arrays in lieu of "smart linked node arrays" which is what it seems like you're heading towards, try just adding a couple variables in your loop body:
byte x_len = Grid.GetLength(0);
byte y_len = Grid.GetLength(1);
byte prev_x, next_x, prev_y, next_y;
for (byte x = 0; x < x_len; ++x)
{
prev_x = x == 0? x_len - 1 : x - 1;
next_x = x == x_len - 1? 0 : x + 1;
for (byte y = 0; y < y_len; ++y)
{
prev_y = y == 0? y_len - 1 : y - 1;
next_y = y == y_len - 1? 0 : y + 1;
// here, you have access to the next and previous
// in both directions, satisfying your requirements
// without confusing your loop variables.
}
}