2016-10-10 136 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。 –