2013-05-31 58 views
6

這是我第一次在這裏,我正在努力解決這個問題。 我有這樣一段代碼:c#ListView.Items [i] .remove非常慢

try 
{ 
    progressBar1.Maximum = lista.Items.Count; 
    lista.BeginUpdate(); 

    for (int i = 0; lista.Items.Count > i; i++) 

    //for (int i = lista.Items.Count - 1; -1 < i; i--) 
    { 
     if (lista.Items[i].SubItems[1].Text.ToLower().Contains(Text) == false) 
     {       
      lista.Items[i].Remove();       
     } 

     progressBar1.Value = progressBar1.Value + 1; 
    } 

    lista.EndUpdate(); 

    progressBar1.Value = 0; 
} 
catch (Exception errore) 
{ 
    txt_info.Text = "" + errore.Message; 
    progressBar1.Value = 0; 
} 

方法lista.items[i].remove是極爲緩慢。 lista是一個ListView,我正在處理大於50,000行的日誌文件。 無論如何加快這個過程?

+3

好奇...... lista.Items.RemoveAt(i)'速度不同嗎?也許(與直覺相反),課堂必須回頭去解決索引本身。 – DonBoitnott

+4

您不應在For循環中更改數據結構的大小(從中刪除項目)。嘗試重新編寫循環,而不刪除它。例如,標記需要在for循環中刪除的索引,然後將它們移出它們。 –

+2

@RezaShirazian一個顯然不能用'foreach'來做......我認爲使用'for'來移除項目是合理的(最終某些代碼必須做到這一點) - 也明顯寫錯了上面的示例是由於跳過剛剛刪除的項目之後的項目)是不好的主意。 –

回答

1
ListViewItem[] allElements = new ListViewItem[listView1.Items.Count]; 
listView1.Items.CopyTo(allElements, 0); 
List <ListViewItem> list = allElements.ToList(); 
list.RemoveAll(item => item.SubItems[1].Text.ToLower().Contains(TextToFind) == false); 
listView1.BeginUpdate(); 
listView1.Clear(); 
listView1.Items.AddRange(list.ToArray()); 
listView1.EndUpdate(); 

第一條規則永遠不會在for循環中更新列表。你的邏輯將只運行到列表的一半。我想這不是你想要的。
我已經看到,即使在使用BeginUpdate和EndUpdate之後,操作listview.items也非常慢。關鍵是在外部進行操作(在列表中),然後用AddRange填充列表(這比Add快得多)。

+0

我已經嘗試了上面的代碼,但給我回空列表。我想念什麼?在你的評論中你說過你正在使用foreach循環,但是我沒有在你離開的代碼中看到它。 – Jarlaxle2k5

+0

@ user2441083:我以前的評論是使用foreach,然後我從列表中刪除元素。但後來我使用了不需要foreach的RemoveAll。順便說一下,列表何時變空了? RemoveAll後?如果是這樣,你需要檢查在「RemoveAll」中寫入的條件是否可以這樣做。 – Yogee

+0

@ user2441083:我在我的應用程序中編寫了相同的邏輯,它工作得很好,速度也不夠快..需要大約2450毫秒才能將列表時間的50,000個條目的列表時間的10%作爲listView1.Items中的LIstViewItems移除。你確定要檢查item.SubItems [1]而不是item.SubItems [0]嗎? – Yogee

3

我會採取不同的方式,並使用LINQ,這樣的事情:

lista.Items = lista.Items.Where(x=>x.SubItems[1].Text.ToLower.Contains(Text)).AsParallel().ToList(); 

基本上,重建列表一次,而不是試圖一遍又一遍移除個別項目。

+1

這是一個很好的緊湊的實現,雖然AsParallel讓我覺得太過分了。 –

+0

ToLower和Contains都是CPU成本計算操作,如果列表很大,它將受益於並行方法 –

+2

['ListView.Items'](http://msdn.microsoft.com/zh-cn/library/system。 windows.forms.listview.items.aspx)是一個只讀屬性,所以這是行不通的。 –

3

最簡單的選擇是使用列表自己的RemoveAll method

list.RemoveAll(x => !x.SubItems[1].Text.ToLower().Contains(Text))

P.S.

您可能想要在實際比較中尋找速度增益。 如果您的要求適合,使用String.Compare要快得多。如果你想檢查一個子字符串,我會建議使用ToUpperInvariant來處理與invariance有關的問題 - it's designed to be faster

+0

['ListViewItemCollection'](http://msdn.microsoft.com/zh-cn/library/system.windows.forms.listview.listviewitemcollection。aspx)沒有'RemoveAll'方法,所以這是行不通的。 –

+0

@Yogee我建議過濾比直接比較快幾倍 - 而不是'Contains'的替代。如果他想使用'Contains',那麼'ToUpperInvariant'會更快。 – Asti

+0

@Yogee SO也可以作爲一般建議的地方。不只是「給我代碼」。儘管如此,我已經編輯它來消除歧義。 – Asti

0

你可以把它放在後臺工作者,並讓它自己做。因此,當這個過程發生時,您的用戶仍然可以使用該程序。