2014-03-31 3 views
0

저는 C#에서 AI 경쟁 항목을 쓰고 있습니다. 항목을 검색하는 좀 더 우아한 방법을 찾고 있습니다. (나는 임베디드 C 프로그래밍에 익숙하지만, AI 컨테스트에 C#을 선호한다.)최대 속성 값을 가진 Enumerable에서 항목 찾기

컨테스트 서버는 dmcs를 사용하여 .Net 프레임 워크 4.0 인 항목을 컴파일한다. 내 테스트를 위해 Visual Studio Express 2013을 사용하고 있습니다.

특정 전제 조건을 만족하는 매개 변수의 최대 값을 가진 목록에서 항목을 검색하려고합니다. 나는 최대 가치를 원하지 않는다. 그러나 나는 최대 가치를 말한 품목을 원한다. 내 모든 코드를 통해 루프 나는 내가 foreach 문이없는이 일을 더 우아한 방법을 찾을려고

List<Region> myList = new List<Region>(); 

// ... 
// myList gets populated with elements 
// ... 

Region biggest = null; 
int biggestSize = -1; 

foreach (Region r in myList) 
{ 
    // We only want elements that are eligible for expansion 
    if (r.EligibleForExpansion()) 
    { 
     if (r.Size > biggestSize) 
     { 
      biggest = r; 
      biggestSize = r.Size; 
     } 
    } 
} 

return biggest; // I want the biggest Region, not the Size of the biggest region. 

:

여기에 내가 foreach 루프를 사용하여 원하는 것을 나의 원래의 코드입니다 . 나는 이것을 시도했다 :

그러나 가장 큰 영역 자체가 아닌 가장 큰 영역의 크기 값을 반환한다.

Max 코드가 -1 (또는 요구 사항을 충족하지 않는 영역)을 제공하는 반면 Region이 요구 사항을 충족시키지 않으면 내 foreach 코드가 null을 반환한다는 것을 알고 있습니다. 나는 어느쪽으로 든 다룰 수있다.

나는 IComparable 영역을 만들 수 있다고 생각하지 않는다. Region 개체에 대한 검색이 많아서 다른 시간에 다른 매개 변수별로 정렬해야하므로 비교 기능이 서로 다른 검색에서 다를 수 있습니다.

정적 함수에서 foreach 코드를 래핑하고 검색 할 필요가있는 곳이면 어디든지 호출 할 수 있지만 C#에서는이를 수행하는보다 우아한 방법이 있어야합니다.

답변

4

사용 MaxBy from moreLINQ library : 그런

public static TSource MaxBy<TSource, TKey>(this IEnumerable<TSource> source, 
    Func<TSource, TKey> selector) 
{ 
    return source.MaxBy(selector, Comparer<TKey>.Default); 
} 

public static TSource MaxBy<TSource, TKey>(this IEnumerable<TSource> source, 
    Func<TSource, TKey> selector, IComparer<TKey> comparer) 
{ 
    if (source == null) throw new ArgumentNullException("source"); 
    if (selector == null) throw new ArgumentNullException("selector"); 
    if (comparer == null) throw new ArgumentNullException("comparer"); 
    using (var sourceIterator = source.GetEnumerator()) 
    { 
     if (!sourceIterator.MoveNext()) 
     { 
      throw new InvalidOperationException("Sequence contains no elements"); 
     } 
     var max = sourceIterator.Current; 
     var maxKey = selector(max); 
     while (sourceIterator.MoveNext()) 
     { 
      var candidate = sourceIterator.Current; 
      var candidateProjected = selector(candidate); 
      if (comparer.Compare(candidateProjected, maxKey) > 0) 
      { 
       max = candidate; 
       maxKey = candidateProjected; 
      } 
     } 
     return max; 
    } 
} 

:이 방법에 대해

var item = myList.Where(x => x.EligibleForExpansion()) 
       .MaxBy(x => x.Size); 
2

? 당신이 널 (NULL)에 초기 값을 포장 수 (그렇지 않은) 값 형식이었다

 var item = myList 
      .Where(r => r.EligibleForExpansion()) 
      .Aggregate((Region)null, (max, cur) => (max == null ? cur : cur.Size > max.Size ? cur : max)); 

Region 경우와 :

myList.Where(r => r.EligibleForExpansion).OrderBy(r => r.Size).LastOrDefault() 
+1

정렬은 _O (n \ * logn) _이며 문제 자체는 선형입니다. – MarcinJuraszek

+0

사실, 비효율적 인 솔루션입니다. 그것의 유일한 이점은 간결성이며, morelinq를 간단하게 가져올 수 있고 잊어 버릴 수도 있다는 점을 고려하면 한계가 있습니다. – Blorgbeard

1

이 목적을 위해 상자 밖으로 Aggregate을 사용할 수 있습니다

 var item = myList 
      .Where(r => r.EligibleForExpansion()) 
      .Aggregate((Region?)null, (max, cur) => (max == null ? cur : cur.Size > max.Value.Size ? cur : max)); 
관련 문제