2011-06-13 121 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; 
}); 

或类似的(也许在一个比较器类,如果是不平凡的)。