当我提取元素时,c#List 的数组是不是被移动?
Posted
技术标签:
【中文标题】当我提取元素时,c#List 的数组是不是被移动?【英文标题】:Is c# List's array being shifted when i extract an element?当我提取元素时,c#List 的数组是否被移动? 【发布时间】:2019-04-05 14:48:54 【问题描述】:我为 Unity 中的任何游戏对象实现了一个通用池系统。 当我从 List 中删除一个 GameObject 时,我总是取最后一个,以避免在 List 的实现中使用的数组发生移位。在互联网上没有找到任何有用的东西,所以试图自己弄清楚。 那有用还是我只是在做无用的代码?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PoolSystem : MonoBehaviour
public static Dictionary<string, List<GameObject>> pool = new Dictionary<string, List<GameObject>>();
#region cached
private static GameObject lastReturned;
#endregion
public static GameObject GetElementFromPool(GameObject g)
if (!pool.ContainsKey(g.name))
lastReturned = Instantiate(g) as GameObject;
pool.Add(g.name, new List<GameObject>());
lastReturned.name = g.name;
return lastReturned;
if (pool[g.name].Count == 0)
lastReturned = Instantiate(g) as GameObject;
lastReturned.name = g.name;
else
lastReturned = pool[g.name][pool[g.name].Count - 1];
pool[g.name].RemoveAt(pool[g.name].Count - 1);
return lastReturned;
public static void AddToPool(GameObject g)
if (!pool.ContainsKey(g.name))
pool.Add(g.name, new List<GameObject>());
pool[g.name].Add(g);
我在答案和cmets中添加了所有建议,感谢大家的帮助。在下面添加更改的代码,也许有人会发现它有用
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PoolSystem : MonoBehaviour
public static Dictionary<string, Stack<GameObject>> pool = new Dictionary<string, Stack<GameObject>>();
#region cached
private static GameObject lastReturned;
private static Stack<GameObject> lastUsedStack;
#endregion
public static GameObject GetElementFromPool(GameObject g)
if (pool.TryGetValue(g.name, out lastUsedStack))
if (pool[g.name].Count == 0)
lastReturned = Instantiate(g) as GameObject;
lastReturned.name = g.name;
else
lastReturned = pool[g.name].Pop();
else
lastReturned = Instantiate(g) as GameObject;
pool.Add(g.name, new Stack<GameObject>());
lastReturned.name = g.name;
return lastReturned;
return lastReturned;
public static void AddToPool(GameObject g)
if (!pool.ContainsKey(g.name))
pool.Add(g.name, new Stack<GameObject>());
pool[g.name].Push(g);
【问题讨论】:
@Neil .NET 列表是基于一个数组的,它是实际上是在移除元素时移动的。双向链表会有可怕的随机访问时间。 作为一个附带问题,不要像那样使用ContainsKey
。请改用TryGetValue
,以避免进行两次哈希查找。
【参考方案1】:
所有索引集合都具有此属性。如果您在任何时候删除一个元素,则以下所有元素都会向上移动。这是您找不到ConcurrentList[T]
的一大原因。制作一个只会让你先进入索引竞争条件。如果不考虑使用代码,就不可能有一个 List 并发。
Keyd Collections (Dictionary[int, GameObject]
) 没有这个缺点。请注意,某些操作有特殊的集合。队列(先进先出)和堆栈(先进后出)。这些可能更适合您的场景。
【讨论】:
堆栈完美地与 O(1) 进行推送和弹出(以及 O(n) 推送成本与完整堆栈),非常感谢! @victordabija:对于那些多任务场景,它甚至还有一个并发变体。【参考方案2】:阅读the documentation
当您调用 RemoveAt 删除一个项目时,列表中的剩余项目将重新编号以替换已删除的项目。例如,如果您删除索引 3 处的项目,则索引 4 处的项目将移动到 3 位置。此外,列表中的项目数(由 Count 属性表示)减少了 1。
此方法是一个 O(n) 操作,其中 n 是 (Count - index)。
【讨论】:
以上是关于当我提取元素时,c#List 的数组是不是被移动?的主要内容,如果未能解决你的问题,请参考以下文章