2016-10-10 132 views
1

我有一个与大量相同类型的对象一起工作的项目。List <>循环优化

现在我使用List<Person>,但是似乎在我有大约1 000 000个项目时循环遍历这个列表是困难的。

循环中,每个Person都有一个被调用的方法,并且有随机生成的新项目,并且有些项目被删除。

我该怎么做才能优化这个循环? 我应该更改集合类型还是将项目移动到数据库?

这是循环的样子:

while (_worldIsLiving) 
{ 
    int beginningPopulation = WorldPopulationNumber; 

    for (int i = 0; i < beginningPopulation; i++) 
    { 
     _worldPopulation[i].InvokeSkills(this); 
    } 

    // Remove dead persons 
    for (int i = 0; i < WorldPopulationNumber;) 
    { 
     if (_worldPopulation[i].IsDead()) _worldPopulation.RemoveAt(i); 
     else i++; 
    } 

    WorldCycles++; 
    if (_hasStopCondition && (WorldPopulationNumber >= WorldMaximumPopulation || WorldPopulationNumber == 0)) 
     Destroy(); 
} 

_worldPopulation[i].InvokeSkills(this);可以产生新的人员。

技能chanceToBeInvokenchanceTobeInherited字段。

+0

迭代速度更快的唯一方法是使用普通数组,但这可能只会产生一个边际差异。任何优化通常都在循环中的代码中,而不是容器中。要回答这个问题,我们需要更多地了解循环中的代码。 –

+2

当你说“循环通过这个列表很难”你是什么意思的“硬”?只需要几个元素就可以轻松循环列表 - 只需要更长的时间。 – Enigmativity

+0

项目存储在内存中。 '人'拥有技能列表,每个技能都有机会被调用。 主循环中的代码:我调用调用随机技能的Person类中的方法。 @MatthewWatson 循环很难,因为一个循环需要大量的项目需要一分钟左右的时间。 @Enigmativity –

回答

3

_worldPopulation.RemoveAt(i)在名单上将是一个昂贵的操作。

它涉及将每个后续项目按位置分流。你在外层循环的每次迭代中多次调用这个函数,每个“死”实例一次。

对于一个长列表,如果我的CS帽子今天被正确佩戴,它将会乘以一个非常显着的开销,其中O(n )复杂。

它可能会快很多只写了一个新的列表:

_worldPopulation = _worldPopulation.Where(p=>!p.IsDead()) 

如果这似乎仍然昂贵,是重要的,在所有的修剪列表? (可以按住列表都活着和死了人口的所有成员,或将这种菌株可用内存?)

,你可以,比如:

var livingPopulace = _worldPopulation.Where(p => !p.IsDead()); 
foreach(var pop in livingPopulace) 
{ 
    pop.InvokeSkills(this) 
} 
var newPopulationCount = _worldPopulation.Count(p => !p.IsDead()); 

虽然这需要2次扫描收集的,与使用RemoveAt相比,这个数字仍然会低于收集的数量,特别是如果每​​个周期的死亡率很高。你回到了复杂的O(n),我怀疑,与大集合,这将是更有效地使用RemoveAt

如果这些都不令人满意,可以考虑使用LinkedList<T>作为容器,它支持简单的前向迭代和低成本移除(以随机访问索引为代价),但也可能存在其他限制,这使得这不切实际。您提供的代码中没有任何内容表明这不起作用。只要不要被Linq运营商(如ElementAt)诱惑就可以避免随机访问的限制,否则你会回到同样的问题。

+0

谢谢,写出一个新的列表而不是'RemoveAt'工作起来更快一些,不确定LinkedList。 –