如何有效地从List 中删除(C#)?

如果我理解正确(如果我错了请纠正我),列表是由.NET中的数组实现的,这意味着列表中每个项目的删除都会导致重新分配所有列表(这反过来意味着O(n) )。

我正在开发一款游戏,在游戏中我有许多子弹在任何给定时刻在空中飞行,让我们说100个子弹,每帧我移动几个像素并检查与游戏中物体的碰撞,我需要删除从列表中每个碰撞的子弹。

所以我在另一个临时列表中收集了碰撞的子弹,然后执行以下操作:

 foreach (Bullet bullet in bulletsForDeletion) mBullets.Remove(bullet); 

因为循环是O(n)并且删除是O(n) ,所以我花费O(n^2 )时间来移除。

有没有更好的方法来删除它,或更合适的集合使用?

创建一个新列表:

 var newList = `oldList.Except(deleteItems).ToList()`. 

尝试尽可能使用function习语。 不要修改现有数据结构,创建新数据结构。

由于散列,该算法为O(N)。

集合和链接列表都具有恒定的时间删除。 你能使用这些数据结构吗?

没有办法避免从List中删除O(N)成本。 如果这对您来说是个问题,您将需要使用不同的数据结构。 它可能会使计算bulletsToRemove的代码感觉更好。

ISet具有很好的方法来计算对象集之间的差异和交叉点。

你通过使用套装丢失了订单,但鉴于你正在使用子弹,我猜这不是问题。 你仍然可以在恒定的时间内枚举它。


在您的情况下,您可以写:

 mBullets.ExceptWith(bulletsForDeletion); 

你不能只从List (相当于Java的ArrayList突出显示)切换到LinkedList吗? LinkedList使用O(1)删除特定元素,但O(n)按索引删除

如何在内部实施列表不是您应该考虑的事情。 您应该与该抽象级别中的列表进行交互。

如果确实存在性能问题,并将其精确定位到列表中,那么现在是时候查看它是如何实现的了。

至于从列表中删除项目 – 您可以使用mBullets.RemoveAll(predicate) ,其中predicate是一个表达式,用于标识已冲突的项目。

RemoveAt(int index)Remove(T item)更快,因为后者使用它里面的第一个,做reflection,这是每个函数里面的代码。

此外, Remove(T)具有IndexOf函数,其中包含第二个循环以评估每个项目的索引。

 public bool Remove(T item) { int index = this.IndexOf(item); if (index < 0) return false; this.RemoveAt(index); return true; } public void RemoveAt(int index) { if ((uint) index >= (uint) this._size) ThrowHelper.ThrowArgumentOutOfRangeException(); --this._size; if (index < this._size) Array.Copy((Array) this._items, index + 1, (Array) this._items, index, this._size - index); this._items[this._size] = default (T); ++this._version; } 

我会做这样的循环:

 for (int i=MyList.Count-1; i>=0; i--) { // add some code here if (needtodelete == true) MyList.RemoveAt(i); } 

根据“usr”建议的function习语的精神,您可能会考虑不从列表中删除。 相反,让您的更新例程采用列表并返回列表。 返回的列表仅包含“仍然活着”的对象。 然后,您可以在游戏循环结束时交换列表(或者,如果适用,立即交换)。 我自己做了这个。