2016-11-02 9 views
3

성능 저하 (10 개) 속성처럼이 MyClass 600000 주위의이 property10까지 property1, property2, 등을 가정 해 봅시다.- 나는 개체의 큰 <code>List<MyClass></code>이

목록에서 일부 속성에 대해 동일한 값을 가진 개체가있는 List<MyClass> 목록을 얻고 싶습니다.

즉, property2, property4, property8property10이 같은 개체를 의미합니다.

가장 좋은 방법은 무엇입니까? 현재 내 List<MyClass>을 통해 루프를 수행하고, 그 루프 내 나는 List<MyClass>.FindAll(), 더미 코드를 통해 모든 유사한 개체를 얻을 :

forach(var item in myClassList) 
{ 
    if(!found.Contains(item)) 
    { 
     var similarObjects = myClassList.FindAll(x => x.property2 == item.property2 && x.property4 == item.property4 && x.property8 == item.property8 && x.property10 == item.property10); 

     //adding the objects to the "already found" list 
     foreach(var foundItem in similarOjbects) 
     { 
     found.Add(foundItem); 
     } 

    if(similarObjects.Count > 1) 
    { 
     similarObjectsList.Add(similarObjects); 
    } 
    } 
} 

을하지만 그것은 List.FindAll() 방법은 매우 느립니다, 나이를합니다.

더 효율적인 알고리즘이 있습니까?

+3

'FindAll' 대신'Where()'를 사용하십시오. – geo

+3

이 큰 목록의 출처는 무엇입니까? SQL 데이터베이스에서 오는 경우 쿼리에 좋은 WHERE 절을 추가하는 것이 더 효율적일 수 있습니다. 또한 목록이 정렬 된 경우 도움이 될 수 있습니다. 그런 다음 해당 순서를 악용하도록 코드를 다시 작성할 수 있습니다. –

+0

@geo : 비슷한 결과를 얻은 것 같습니다. – flo

답변

4

당신은 매우 효율적으로이 문제를 해결하기 위해 group by를 사용할 수 있습니다

당신에게 각 그룹은 동일한있는 모든 객체를 포함하는 그룹의 순서를 줄 것이다
var grouped = 
    from item in myClassList 
    group item 
    by new {item.Property2, item.Property4, item.Property8, item.Property10}; 

지정된 등록 정보의 값. 예를 들어

, 당신은 이런 식으로 뭔가를 할 수 그룹의 결과 시퀀스의 각 그룹에있는 모든 항목을 반복하기 :이 각 속성의 유형을 구현 있다고 가정

foreach (var group in grouped) 
{ 
    foreach (var item in group) 
    { 
     // Do something with item 
    } 
} 

참고 IEquatable<T>GetHashCode() .출력 위

using System; 
using System.Collections.Generic; 
using System.Linq; 

namespace Demo 
{ 
    class Data 
    { 
     public string Name { get; set; } 
     public int Property1 { get; set; } 
     public int Property2 { get; set; } 
     public int Property3 { get; set; } 
     public int Property4 { get; set; } 
     public int Property5 { get; set; } 
     public int Property6 { get; set; } 
     public int Property7 { get; set; } 
     public int Property8 { get; set; } 
     public int Property9 { get; set; } 
     public int Property10 { get; set; } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      List<Data> myClassList = new List<Data> 
      { 
       new Data {Name = "1A", Property2 = 1, Property4 = 1, Property8 = 1, Property10 = 1}, 
       new Data {Name = "1B", Property2 = 1, Property4 = 1, Property8 = 1, Property10 = 1}, 
       new Data {Name = "1C", Property2 = 1, Property4 = 1, Property8 = 1, Property10 = 1}, 
       new Data {Name = "2A", Property2 = 2, Property4 = 2, Property8 = 2, Property10 = 2}, 
       new Data {Name = "2B", Property2 = 2, Property4 = 2, Property8 = 2, Property10 = 2}, 
       new Data {Name = "2C", Property2 = 2, Property4 = 2, Property8 = 2, Property10 = 2}, 
       new Data {Name = "3A", Property2 = 3, Property4 = 3, Property8 = 3, Property10 = 3}, 
       new Data {Name = "3B", Property2 = 3, Property4 = 3, Property8 = 3, Property10 = 3}, 
       new Data {Name = "3C", Property2 = 3, Property4 = 3, Property8 = 3, Property10 = 3}, 
      }; 

      var grouped = 
       from item in myClassList 
       group item 
       by new {item.Property2, item.Property4, item.Property8, item.Property10}; 

      foreach (var group in grouped) 
      { 
       Console.WriteLine(string.Join(", ", group.Select(item => item.Name))); 
      } 
     } 
    } 
} 

예 :, 당신은 할 수 아래 @BertPersyn에서 언급 한 바와 같이 PLINQ

를 사용

1A, 1B, 1C 
2A, 2B, 2C 
3A, 3B, 3C 

가능한 최적화 여기

은 컴파일 가능한 예제 PLINQ를 사용하여 속도를 높일 수도 있습니다.

는이를 위해 단순히 (.AsParallel()의 추가주의) grouped을 생성하려면 다음을 사용 :

var grouped = 
    from item in myClassList.AsParallel() 
    group item 
    by new {item.Property2, item.Property4, item.Property8, item.Property10}; 

가 확인하려면이 실제로 일을 속도를하는 경우, 당신이 어떤 타이밍을 수행하는 것이 필수적이다.

+1

CLR이 허용하는 경우 병렬 클래스를 사용해보십시오. –

+0

@BertPersyn 좋은 아이디어, 나는 대답에 그것을 추가 할 것이다. –

+0

감사합니다. 나는 나중에 그것을 시험해보고 그것이 어떻게 수행되었는지 알려줄 것이다. – flo

2

먼저 클래스에 고유 키 (해시)를 반환하는 GetUniqueKey 메서드를 추가합니다. 그런 다음

, 사용은 비슷한 키를 사용하여 항목을 찾을 수 그룹화 :

List<List<Item>> = items 
    .GroupBy(item => item.GetUniqueKey()) 
    .Select(g => g.ToList()) 
    .ToList(); 

GetUniqueKey 방법은 필요한 속성 유형을 기반으로 구현하고 최적화해야합니다.

GetUniqueKey 예 방법 자체가 최적화되지 않을 수 있습니다
public object GetUniqueKey() 
{ 
    return new { P1 = Prop1, P2 = Prop2 }; 
} 

, 다른을 찾을 수

public string GetUniqueKey() 
{ 
    return Prop1.ToString() + "-" + Prop2.ToString(); 
} 

OR (더 최적화) : 속성 1과 Property2 정수는 예를 들어, 다음과 같은 방법을 사용할 수 있습니다 최적화 된 구현.

전체 예 :

class Item 
{ 
    public int Prop1 {get; set;} 

    public int Prop2 {get; set;} 

    public string GetUniqueKey() 
    { 
     return Prop1.ToString() + "-" + Prop2.ToString(); 
    } 
} 

public void DoWork() 
{ 
    Random rnd = new Random(); 

    List<Item> items = new List<Item>(); 

    for(int i = 0; i < 600000; i++) 
    { 
     items.Add(new Item { Prop1 = rnd.Next(1, 10) }); 
    } 

    for(int i = 0; i < 600000; i++) 
    { 
     items[i].Prop2 = rnd.Next(1, 13); 
    } 

    List<List<Item>> = items 
     .GroupBy(item => item.GetUniqueKey()) 
     .Select(g => g.ToList()) 
     .ToList(); 
} 
+0

동일하지만, 나중에 다시 시도해보고 결과를 알려 드리겠습니다. 현재 두 답변을 모두 시험해보기를 기대합니다! – flo

+0

여기에서 - 10 시간에서 8 초까지 - 또한 대단히 감사합니다. Mathews는 읽는 것이 더 쉽고 수업에 추가 방법을 추가 할 필요가 없기 때문에 답변을 표시합니다. 그럼에도 불구하고, 많은 감사합니다! – flo

관련 문제