I'm trying to write a model containing digital organisms. Within the model i'd liek the environment to be a fixed 2-d array, but each cell needs to contain a list of the organisms in it. I tried using a jagged array, but as the number of occupied elements varies quite a bit throughout the programm run, i need to use something more flexible than an array. I've tried making a 2-D array of the type list, but im getting errors with it.
List<Creature>[,] theWorld;
public Environment()
{
List<Creature>[,] theWorld = new List<Creature>[100,100];
}
public void addCreature(Creature c)
{
for (int x = 0; x < 100; x++)
{
for (int y = 0; y < 100; y++)
{
theWorld[x, y].Add (c);
} } }
this is the segment where i'm trying to declare the array at the beginning, as a type that holds lists (of the organisms), and later i try to add a creature (c) to each of the lists in each element of the array.
when i run it i get the following error message-
"An unhandled exception of type 'System.NullReferenceException' occurred in HGT_sim_2.exe
Additional information: Object reference not set to an instance of an object."
and the line "World[x, y].Add (c);" is highlighted.
If anyone can tell me what i'm doing wrong, and even better, a way around the problem, it'd be amazing.
thank you ain advance!
All your array contains initially is a lot of nulls. You need to actually create the lists...
for(int x = 0 ; x < 100 ; x++)
for(int y = 0 ; y < 100 ; y++)
theWorld[x,y] = new List<Creature>();
Personally, though, I expect this will be a costly way to do things...
It depends in part on whether the data is "sparse" - i.e. are most of the cells usually taken? A simple (but possibly more efficient) approach, for example, would be to use something like multi-map; i.e.
Point pt = new Point(x,y);
theWorld.Add(pt, someCreature);
where theWorld could be something like EditableLookup<Point, Creature> (using EditableLookup<,> from "MiscUtil"). That way, you can still query it by co-ordinate, and have multiple creatures on a coordinate, but you don't have to allocate space for every cell. And because it functions as a dictionary it is still fast. Not as fast as a flat array, but it will scale to bigger (sparse) grids... of course, if the grid has creatures on every cell it could be more expensive! Hence the need to understand your data.
You need to initialize each member of your array, e.g.
for (int x = 0; x < 100; x++)
{
for (int y = 0; y < 100; y++)
{
theWorld[x, y] = new List<Creature>();
} }
Here's the fix:
List<Creature>[,] theWorld;
public Environment()
{
theWorld = new List<Creature>[100,100]; // Remove the type, you were creating a new list and throwing it away...
for(int x = 0 ; x < 100 ; x++)
for(int y = 0 ; y < 100 ; y++)
theWorld[x,y] = new List<Creature>();
}
public void addCreature(Creature c)
{
for (int x = 0; x < 100; x++)
{
for (int y = 0; y < 100; y++)
{
theWorld[x, y].Add (c);
} } }
When you do this:
List<Creature>[,] theWorld = new List<Creature>[100,100];
You're creating an array of List<Creature> references, but they are all empty (pointing to null, not a valid List). You need to initialize each individual element:
for (int x = 0; x < 100; x++) {
for (int y = 0; y < 100; y++) {
theWorld[i,j] = new List<Creature>();
}
}
Once you've done that, you'll be able to call .Add on the individual members.
You're doing it almost correct. Your variable is a 2D array of List<Creature>. Now, List<Creature> is a reference type, so the array is initialized to contain null's in all its members. Thus you get the NullReferenceException. The line
theWorld[x, y].Add (c);
is basically equivalent to
null.Add (c);
All you need to do is to initialize all the members to contain instances of List<Creature>. The best way to do this would be in the constructor. Just rewrite it like this:
public Environment()
{
theWorld = new List<Creature>[100,100];
for(int x = 0 ; x < 100 ; x++)
for(int y = 0 ; y < 100 ; y++)
theWorld[x,y] = new List<Creature>();
}
Now all the operations will work as expected.
Also note, that in your example you are creating a local variable with the same name as the class member. This way you don't initialize the class member at all - it stays null.
You have created the array object to hold your lists, but you haven't created the list itself. You will need to do the following in your constructor:
for (int x = 0; x < 100; x++)
for (int y = 0; y < 100; y++)
theWorld[x,y] = new List<Creature>();
Another problem: you were also defining theWorld as a local variable in your constructor, which means your theWorld field on Environment was never initialized, either.
However, 10,000 Lists may be overkill for what you really need. If your Environment really needs a Creature at every point, and some Creatures may move to other points (where there is more than one at a point, then it may make more sense to use a Dictionary<Point, IList<Creature>> as your model versus 10,000 lists.
public void Add(Creature c, Point at)
{
IList<Creature> list;
if (!theWorld.TryGetValue(at)) {
list = theWorld[at] = new List<Creature>();
}
list.Add(c);
}
You can then implement Move and Remove methods similarly. Also, note that you are adding the same Creature to every point, which (may) mean that there's one Creature at all points in your Environment. You will probably want to create a new Creature() for every point, if that's what you are actually modeling.
Related
So I have this for loop:
for (int i = 0; i < meshes.Count; i++)
{
for (int j = 0; j < meshes.Count; j++)
{
for (int m = 0; m < meshes[i].vertices.Length; m++)
{
for (int n = 0; n < meshes[i].vertices.Length; n++)
{
if ((meshes[i].vertices[m].x == meshes[j].vertices[n].x) && (meshes[i].vertices[m].z == meshes[j].vertices[n].z))
{
if (meshes[i].vertices[m] != meshes[j].vertices[n])
{
meshes[i].vertices[m].y = meshes[j].vertices[n].y;
}
}
}
}
}
}
Which goes through a few million vectors and compares them to all other vectors, to then modify some of their y values. I think it works, however after hitting play it takes an unbelievably long time to load (currently been waiting for 15 minutes, and still going). Is there a way to make it more efficient? Thanks for the help!
As I read this, what you're basically doing, is that for all vertices with the same x and z, you set their y value to the same.
A more optimized way would be to use the Linq method GroupBy which internally uses hash mapping to avoid exponential time complexity like your current approach:
var vGroups = meshes.SelectMany(mesh => mesh.vertices)
.GroupBy(vertex => new { vertex.x, vertex.z });
foreach (var vGroup in vGroups)
{
vGroup.Aggregate((prev, curr) =>
{
// If prev is null (i.e. first iteration of the "loop")
// don't change the 'y' value
curr.Y = prev?.y ?? curr.y;
return curr;
});
}
// All vertices should now be updated in the 'meshes'
Note, that the final y value of the vertices depends on the order of the meshes and vertices in your original list. The first vertex in each vGroup is the deciding vertex. I believe it'll be opposite of your approach, where it's the last vertex that's the deciding one, but it doesn't sound like that's important for you.
Furthermore, be aware that in this (and your) approach you are possibly merging two vertices in the same mesh if two vertices have the same x and z values. I don't know if that's intended but I wanted to point it out.
A additional performance optimization would be to parallelize this. Just start out with call to AsParallel:
var vGroups = meshes.AsParallel()
.SelectMany(mesh => mesh.vertices)
.GroupBy(vertex => new { vertex.x, vertex.z });
// ...
Be aware, that parallelization is not always speeding things up if the computation you are trying to parallelize is not that computationally expensive. The overhead from parallelizing it may outweigh the benefits. I'm not sure if the GroupBy operation is heavy enough for it to be beneficial but you'll have to test that out for yourself. Try without it first.
For a simplified example, see this fiddle.
You want to make Y equal for all vertices with the same X and Z. Lets do just that
var yForXZDict = new Dictionary<(int, int), int>();
foreach (var mesh in meshes)
{
foreach (var vertex in mesh.vertices)
{
var xz = (vertex.x, vertex.z);
if (yForXZDict.TryGetValue(xz, out var y))
{
vertex.y = y;
}
else
{
yForXZDict[xz] = vertex.y;
}
}
}
You should replace int to the exact type you use for coordinates
You are comparing twice unnecessarily.
Here a short example of what I mean:
Let's say we have meshes A, B, C.
You are comparing
A, A
A, B
A, C
B, A
B, B
B, C
C, A
C, B
C, C
while this checks e.g. the combination A and B two times.
One first easy improvement would be to use e.g.
for (int i = 0; i < meshes.Count; i++)
{
// only check the current and following meshes
for (int j = i; j < meshes.Count; j++)
{
...
do you even want to compare a mesh with itself? Otherwise you can actually even use j = i + 1 so only compare the current mesh to the next and following meshes.
Then for the vertices it depends. If you actually also want to check the mesh with itself at least you want int n = m + 1 in the case that i == j.
It makes no sense to check a vertex with itself since the condition will always be true.
A next point is minimize accesses
You are accessing e.g.
meshes[i].vertices
five times!
rather get and store it once like e.g.
// To minimize GC it sometimes makes sense to reuse variables outside of a loop
Mesh meshA;
Mesh meshB;
Vector3[] vertsA;
Vector3[] vertsB;
Vector3 vA;
Vector3 vB;
for (int i = 0; i < meshes.Count; i++)
{
meshA = meshes[i];
vertsA = meshA.vertices;
for (int j = i; j < meshes.Count; j++)
{
meshB = meshes[j];
vertsB = meshB.vertices;
for(int m = 0; m < vertsA.Length; m++)
{
vA = vertsA[m];
...
Also note that a line like
meshes[i].vertices[m].y = meshes[j].vertices[n].y;
Actually shouldn't even compile!
The vertices are Vector3 which is a struct so assigning the
meshes[i].vertices[m].y
only changes the value of a returned Vector3 instance but shouldn't in any way change the content of the array.
You would rather work with the vA as mentioned before and at the end assign it back via
vertsA[m] = vA;
and then at the end of the loop assign the entire array back once via
meshA.vertices = vertsA;
And well finally: I would put this into a Thread or use Unity's JobSystem and the burst compiler and meanwhile e.g. display a progress bar or some User feedback instead of freezing the entire application.
Yet another point is floating point precision
you are directly comparing two float values using ==. Due to the floating point precision this might fail even if it shouldn't e.g.
10f * 0.1f == 1f
is not necessarily true. It might be 0.99999999 or 1.0000000001.
Therefore Unity uses only a precision of 0.00001 for Vector3 == Vector3.
You should either do the same and use
if(Mathf.Abs(vA.x - vB.x) <= 0.00001f)`
or use
if(Mathf.Approximately(vA.x, vB.x))
which equals
if(Mathf.Abs(vA.x - vB.x) <= Mathf.Epsilon)`
where Epsilon is the smallest value two floats can differ
How can I loop through the values that are returned from a specified range?
I tried the following code but it returns:
Cannot apply indexing with [] to an expression of type 'System.Array'
var rng = (Excel.Range)sheet.Range[sheet.Cells[3, 2], sheet.Cells[3, 27]];
var wsValues = rng.Cells.Value;
for (var j = 0; j < wsValues.Length; j++)
{
var test = wsValues[j];
}
Its a system array not a 'normal array' (based upon the error). So you should be able to use var test = wsValues.GetValue(1, j); Note this will return an object. So you will have to do a cast to your expected type.
Also note that the 1 in that case is because all your test data has 1 as your first value in your multidimensional array. You can view a multidimensional array as a grid, with an x co-ordinate and a y co-ordinate, so if you wanted to iterate through them properly (as if you were using up multiple columns instead of just one). Then you would do:
for (var x = 1; x <= wsValues.GetLength(0); x++)
{
for (var y = 1; y <= wsValues.GetLength(1); y++)
{
var test = wsValues[x, y];
}
}
In this the GetLength command returns the length of that dimension, so the first one returns the length of how many 'columns' or the maximum x value there are, and the second one returns the maximum y value or how many rows there are.
I'm currently working on a game where the background is represented by a 2D array of tiles. Tile is a relatively simple class that contains graphic and traversability information. In my code, I find myself wanting to do something similar to the following often:
for (int x = 0; x < TileMap.GetLength(0); x++)
{
for (int y = 0; y < TileMap.GetLength(1); y++)
{
// do something
}
}
Obviously there's a better way to do that, right? I thought that maybe I could create an extension method that takes an Action parameter that iterates through the array and performs the specified action for each Tile, like so:
public static void PerformAction(this Tile[,] tileMap, Action<Tile> action)
{
for (int x = 0; x < tileMap.GetLength(0); x++)
{
for (int y = 0; y < tileMap.GetLength(1); y++)
{
action(tileMap[x, y]);
}
}
}
And then use it like this (just an example):
TileMap.PerformAction(t => t = new Tile());
This doesn't work, though. I can set a breakpoint in either the extension method or in the lambda expression and watch it get hit each iteration, but the actual Tile in the TileMap remains unchanged. For the example above, all Tiles are still null if they were null before. Am I doing something wrong? Is there a better way to do what I want to do?
From your description, it sounds like you want to be able to modify the element in the array itself, not just the object it references (or value it stores…it's not clear whether Tile is a class or a struct). Of course, invoking an Action<T> delegate, you're just passing the value from the array to the method, not a reference to the element of the array. The delegate has no way to modify the array itself in that scenario.
One way to fix this is to pass the element of the array by-reference instead of the default by-value. The built-in delegate types don't support by-reference parameter passing. But you can declare your own delegate (see this answer for more details):
delegate void ActionRef<T>(ref T t);
Then you can implement your extension method like this:
public static void PerformAction(this Tile[,] tileMap, ActionRef<Tile> action)
{
for (int x = 0; x < tileMap.GetLength(0); x++)
{
for (int y = 0; y < tileMap.GetLength(1); y++)
{
action(ref tileMap[x, y]);
}
}
}
Passing a delegate from a method like this:
void MyActionMethod(ref Tile tile)
{
// do something to tile
}
An alternative approach (and IMHO maybe somewhat cleaner) would be to have the action delegate return a new value if desired:
public static void PerformAction(this Tile[,] tileMap, Func<Tile, Tile> action)
{
for (int x = 0; x < tileMap.GetLength(0); x++)
{
for (int y = 0; y < tileMap.GetLength(1); y++)
{
tileMap[x, y] = action(tileMap[x, y]);
}
}
}
Then your method might look something like this:
Tile MyActionMethod(Tile tile)
{
// do something to tile
return tile;
}
I have list called “images” which is contained of the series of bitmap images.
My question is how can I loop through every single element of my “images” list and do this operation for different elements of my list “images”?
You want to keep collections for each element of images, right?
You'll need to maintain a list of lists, or something similar:
List<List<int>> stuffOfImages = new List<List<int>>();
for (int x = 0; x < images[i].Width; x++) {
var stuffOfImage = new List<int>();
stuffOfImages.Add(stuffOfImage);
for (int y = 0; y < images[i].Height; y++) {
}
}
Note that you lose all reference to the associated image - it might be worthy creating a type so you can keep a reference to the image and the integer collection associated with it in one place and related.
I'm a little unclear as to what you mean, so please elaborate if necessary.
Making game of life I need to a have a grid that is 30x20 (X * Y). The problem is (I had another question regarding to that) that the c# arrays are rows, columns. So when I use CursorPosition() to drawing I need to swap it because it wants column at first.
Is there any way how I can reverse it so I can use like this?
int [,] Array = new int[30,20];
Console.SetCursorPosition(29,19) // now its vice versa, I would need to use 19,29.
I believe that this is purely conceptual (c# arrays are neither row/col or col/row that is up to the developer) and comes down to iterating your array in either a depth-first or breadth-first manner e.g.
//Breadth-first
for(int x = 0; x < col.Length; x++)
{
for(int y = 0; y < row.Length; y++)
{
}
}
//Depth-first
for(int y = 0; y < row.Length; y++)
{
for(int x = 0; x < col.Length; x++)
{
}
}
At first I was inclined to answer no as the parameters to Console.SetCursorPosition is Positional parameters. But when I remember that C# have Named parameters too so something like this works.
int a = 10;
int b = 20;
Console.SetCursorPosition(top: a, left: b);
This is the closest you can get, if you want to know why, search for the terms above
What you need is a data structure to store date in relation with an x,y coordinate.
You do not have to use a multi-dimensional array for this. You could very easily create a class that hides the specific implementation from the other classes.
In fact this will make your design more robust.
You can store the data in a database, bitarray, single dimension array, etc.