2011-06-13 120 views
5

目前,我整理使用LINQ to對象,然後做的結果ToList()列表:轉換LINQ排序依據,以就地列表排序

var SortedPossibleMoveLocations = (from PML in PossibleMoveLocations 
            orderby Randomiser.Next() 
            orderby IsSameType(PML) ? (_Owner[PML] as TileFlowing).UnitsWithin : 0 
            orderby PossibleMoveLocationOrdering(PML) 
            select PML).ToList(); 

我想將它轉換爲做一個就地排序,我猜測使用List<T>.Sort()方法。如果我只是訂購一件事,我會知道如何做到這一點,但是,因爲我訂購PossibleMoveLocationOrdering(其返回int),然後IsSameType(PML) ? (_Owner[PML] as TileFlowing).UnitsWithin : 0其計算結果爲int,然後由Randomiser.Next()(它返回一個隨機int )我不知道該怎麼做。

問題:我該如何編寫比較函數(或者是否有更好的方法)來執行上述的LINQ查詢。

+2

請注意,多個orderby幾乎總是*錯誤* - 不會添加'ThenBy',因此它實際上會反轉排序優先順序。它應該是一個orderby與多個表達式 – 2011-06-13 09:22:49

+0

我知道我會得到與x,y,z秩序相反的命令。 (雖然我確實寫過這個之前,我知道單順序的語法)。這就是爲什麼在下面的代碼中我明確了什麼是主持人。謝謝你的信息。 – 2011-06-13 09:28:05

回答

10

首先,指定三個orderby子句是一個壞主意 - 相反,只需使用逗號分隔指定多個排序。

我也不熱衷於使用Randomiser.Next()進行排序的想法,但這是一個問題。

你的LINQ查詢應該這個樣子(仍與Randomiser在目前):

var query = (from PML in PossibleMoveLocations 
      orderby PossibleMoveLocationOrdering(PML), 
        IsSameType(PML) ? (_Owner[PML] as TileFlowing).UnitsWithin : 0, 
        Randomiser.Next() 
      select PML).ToList(); 

個人而言,我只希望用點符號此:

var query = PossibleMoveLocations 
       .OrderBy(pml => PossibleMoveLocationOrdering(PML)) 
       .ThenBy(pml => IsSameType(pml) ? 
            (_Owner[pml] as TileFlowing).UnitsWithin : 0) 
       .ThenBy(pml => Randomiser.Next()) 
       .ToList(); 

排序在原地,您基本上需要一個Comparison<T>IComparer<T>它可以測試多個東西,也是一個使用屬性創建比較器的實現。你可以這樣做手工(根據馬克的代碼),但因爲它發生,我有一些輔助類和擴展方法在MiscUtil

var comparer = ProjectionComparer<PossibleMove> 
        .Create(pml => PossibleMoveLocationOrdering(PML)); 
        .ThenBy(pml => IsSameType(pml) ? ...) 
        .ThenBy(...); 

list.Sort(comparer); 

注意,使用這裏Randomizer絕對一個糟糕的主意,因爲它會在每次比較時調用(對於具有相同第一部分的對象)...這會導致不一致的比較,以至於x < y < z < x

+0

在最後一個隨機數orderbyby(所有其他順序的值是相等的)情況下,會有什麼替代方法? – 2011-06-13 09:30:43

+0

另外,純粹是因爲可讀性,使用多個orderby的一個壞主意,還是有另一個原因? – 2011-06-13 09:31:24

+0

@George:基本上你在這種情況下沒有一致的順序。如果不能一致地區分兩個對象,爲什麼不比較它們時返回0呢? – 2011-06-13 09:31:48

6

最常見的是:

list.Sort((x,y) => { 
    int result = /* first comparison, for example 
        string.Compare(x.Name, y.Name) */ 
    if (result == 0) result = /* second comparison, 
           for example x.Id.CompareTo(y.Id) */ 
    ... 
    if (result == 0) result = /* final comparison */ 
    return result; 
}); 

或類似的(也許在一個比較器類,如果是不平凡的)。