2014-03-31 56 views
0

我正在爲C#中的AI競賽撰寫條目,並且正在尋找更優雅的方式來搜索項目。 (我對嵌入式C編程更加熟悉,但我更喜歡C#進行AI競賽。)在Enumerable中查找具有最大屬性值的項目

比賽服務器使用dmcs編譯條目,即.Net Framework 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循環都在我的代碼。我嘗試這樣做:

return myList.Max(delegate(Region r) { if (r.EligibleForExpansion()) return r.Size; else return -1; }); 

然而,返回最大的區域,而不是最大的地區本身的大小值(這是我所需要的)。

我知道我的foreach代碼將返回null,如果沒有區域滿足要求,而最大代碼將給-1(或任何區域不符合要求);我可以處理任何一種方式。

雖然我不認爲我可以製作Region IComparable,我有很多區域對象的搜索,我需要在不同的時間按不同的參數排序,所以比較函數在不同的搜索中會有所不同。

我可以將我的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

這個怎麼樣?

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

排序是_O(n \ * logn)_,而問題本身是線性的。 – MarcinJuraszek

+0

確實如此,這是一個效率低下的解決方案。它唯一的優點是簡潔,考慮到更多的林林可以簡單地導入和遺忘,這是一個邊緣。 – Blorgbeard

1

您可以使用Aggregate開箱即用於此目的:

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

如果Region是一個值類型(它不是),你可以在一個可空包的初始值,併爲空列表獲得空值:

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