2013-05-31 17 views
6

ここは初めてのことであり、この問題を解決するのに苦労しています。非常に遅いですlista.items[i].removec#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; 
} 

方法: は、私はこのコードの部分を持っています。 listaListViewで、50,000行以上のログファイルを作成しています。 処理を高速化する方法はありますか?

+3

奇妙なことに、「lista.Items.RemoveAt(i)」のスピードは異なりますか?おそらく(直感的に反して)クラスは戻ってインデックス自体を解決しなければなりません。 – DonBoitnott

+4

Forループ内でデータ構造体のサイズを変更しないでください(項目を削除する)。ループを削除せずにループを書き直してみてください。たとえば、forループで削除する必要のあるインデックスにフラグを立て、そのインデックスの外にそれらを削除します。 –

+2

@RezaShirazian Oneは明らかに '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を使用しました。 Btw、いつリストは空になりますか? RemoveAllの後に?もしそうなら、あなたは "RemoveAll"で書かれた条件がそうするかもしれないかどうか確認する必要があります。 – Yogee

+0

@ user2441083:私のアプリケーションで同じロジックを書いていますが、十分に高速で動作しています。listView1.ItemsのLIstViewItemsとして2次元文字列の50,000エントリのリスト時間の10%を取り除くために2450ミリ秒かかります。 item.SubItems [0]ではなくitem.SubItems [1]を確認してもよろしいですか? – 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/en-us/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を使用することをお勧めします。it's designed to be faster

+0

['ListViewItemCollection'](http://msdn.microsoft.com/en-us/library/system.windows.forms.listview.listviewitemcollection。aspx)は 'RemoveAll'メソッドを持っていないので、これは動作しません。 –

+0

@Yogee私は、フィルタリングが直接比較のために数倍高速であることを示唆していました。彼が 'Contains'を使いたい場合、' ToUpperInvariant'はより速いです。 – Asti

+0

@Yogeeは一般的なアドバイスの場でもあります。単に "私にtehコードを渡す"だけではありません。それにもかかわらず、私はあいまいさを取り除くためにそれを編集しました。 – Asti

0

あなたはバックグラウンドワーカーにそれを貼り付けることができ、それを自分自身で行うことができます。したがって、このプロセスが発生している間もユーザーはプログラムを使用できます。