2013-05-31 2 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 매우 느린 : 나는이 코드 조각이있다. listaListView이고 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을 사용했습니다. 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 및 포함은 모두 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.

실제 비교에서 속도를 향상시킬 수 있습니다. String.Compare을 사용하면 요구 사항이 맞으면 훨씬 빠릅니다. 하위 문자열을 확인하려면 불변 관계 문제 (it's designed to be faster)에 ToUpperInvariant을 사용하는 것이 좋습니다.

+0

['ListViewItemCollection'] (http://msdn.microsoft.com/en-us/library/system.windows.forms.listview.listviewitemcollection.aspx)에는'RemoveAll' 메서드가 없으므로 작동하지 않습니다. –

+0

@ Yogee 필자는 직접 비교를 위해 필터링이 여러 번 더 빠르다고 제안했다. 그가 'Contains'를 사용하고 싶다면, ToUpperInvariant가 빠릅니다. – Asti

+0

@ Yogee는 일반적인 조언을 구할 수있는 곳이기도합니다. "teh code"를주는 것이 아닙니다. 그럼에도 불구하고 나는 애매 모호함을 제거하기 위해 그것을 편집했다. – Asti

0

당신은 배경 작업자에게 그것을 붙일 수 있고, 그것을 자신의 것으로 할 수 있습니다. 따라서이 프로세스가 진행되는 동안 사용자는 여전히 프로그램을 사용할 수 있습니다.