简体   繁体   中英

C# exceedingly long execution time on List<T>.Find()

I'm using C# to build a game that involves a grid-based map system. I'm storing the grid system in a List object where T is a type that contains position and other data. Upon calling a function that finds a tile's neighbors, I've run into an extreme delay in execution. I've narrowed the delay down to a call to the Find() method of my List. The method looks like this:

list.Find(tile => tile.X == x && tile.Y == y)

Why is this causing such immense lag? Is there any better alternative to storing my tiles in a List?

Find is O(n) where n is the list's Count. If you are always doing lookups by coordinate pairs, a Dictionary could really help since you get O(1) lookups on the key. You could start with a Dictionary<Tuple<int,int>, Tile> and see if that suits your needs. Obviously whether a Dictionary is better in the long run depends on the size of the list and the kind of lookups you need to do.

If your map is square/rectangular and of a fixed size (or a variable size but which changes infrequently), them you will likely get much better performance by using a 2-dimensional array, and accessing the tiles by index.

You don't indicate whether the x and y values are tile indices or are related to a coordinate contained within the tile. Either way, you can presumably calculate an index for each tile, such that for n tiles, the indices run from 0..n-1 , that could be used to index into an array.

You could define your map array as:

Tiles[,] map = new Tiles[numXTiles, numYTiles];

Then accessing the tile is as easy as:

var tile = map[x, y];

There are indications that multi-dimensional arrays are lower performing than jagged arrays, but multidimensional arrays are easier to create, and have (in my opinion) nicer syntax. If this is still an issue, you could either move to using a jagged array, or use a single-dimensional array, and calculate the indices as: x + y * numXTiles .

If you frequently do the same kind of query, like in your case, it makes sense to use an indexer on a combined key to retrieve the object because an indexer usually has a more or less constant performance. Meaning the time to find the object does not increase if the number of objects increase...

To do so, use a Dictionary where TKey is for example a string and each key is tile.X + " " + tile.Y for example. To retrieve the object, you just have to call dic[tile.X + " " + tile.Y]

Since in that lambda expression you are implying you know the x and y coordinates, you are much better off using a 2D array as already suggested. LINQ is great, but it shouldn't be used everywhere.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM