简体   繁体   中英

c# ListView.Items[i].remove is very slow

It is my first time here and I am struggling to solve this issue. I have this piece of code:

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;
}

The method lista.items[i].remove is extremely slow. lista is a ListView and I am working on a log file bigger than 50,000 lines. Is there anyway to speed up the process?

I would take a different approach and use LINQ, something like this :

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

Basically, rebuilding the list once rather than trying to remove individual items over and over again.

The simplest option would be to use the list's own RemoveAll method .

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

PS

You might want to look for speed gains in the actual comparison. Using String.Compare is much faster if your requirement fits it. If you want to check for a sub-string, I would suggest using ToUpperInvariant for invariance related matters - it's designed to be faster .

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();

First Rule is never update list in for loop. Your logic will only run till half of the list. I guess that's not what you want.
I've seen that manipulating listview.items is very slow even after using BeginUpdate and EndUpdate. Key is to do the manipulation outside (in list or so) and then re populate the list with AddRange (which is much faster than Add).

You could stick it in a background worker and have it do this on it's own. Therefore your users could still use the program while this process is occuring.

If you remove an item in for loop, you should set the counter to 1 less so you won't miss one. Because you remove [i], [old i+1] becomes the [new i] (Items.Count decreases 1 also) and you will miss checking the [new i].

eg: ListView.Items.Remove[i]; i--;

Lists are slow to access dynamically and much better suited to iteration. I would suggest manipulating the data outside of the listview (maybe by copying the rows you want to display into a temporary list one at a time as you iterate across the source collection) and then assigning to the listview at the end. This can be done on a different thread (to improve UI performance) and doesn't require expensive lookups.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM