2011-06-13 30 views
5

Şu INPLACE listeye LINQ OrderBy dönüştürme i sonra sonuçlar üzerinde ToList() yapıyor, nesnelere LINQ kullanarak bir liste ayırıyorum:sıralama

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

Bu INPLACE sıralama bir yapmak dönüştürmek istediğiniz i List<T>.Sort() yöntemini kullanarak tahmin edin. Eğer sadece bir şey tarafından sipariş veriyor olsaydım, bunun nasıl yapılacağını bilirdim, ancak PossibleMoveLocationOrdering (bir int döndürür) sonra, sonra Randomiser.Next() (o zaman rastgele bir int döndüren) değerlendiren IsSameType(PML) ? (_Owner[PML] as TileFlowing).UnitsWithin : 0) Bunu nasıl yapacağımı bilmiyorum.

Soru: Yukarıdaki LINQ sorgusunun bir sıralama türünü yapmak için karşılaştırma işlevini (veya daha iyi bir yöntem var mı) yazarım. En yaygın

+2

Çoklu komut dizisinin hemen hemen her zaman * yanlış olduğunu unutmayın - bu 'ThenBy'yi eklemez, bu nedenle aslında sıralama önceliğini tersine çevirir. Birden fazla ifade –

+0

ile tek bir sipariş olmalıdır Ben anlıyorum sipariş x, y, z tersi sipariş alacağım. (Bunu daha önce yazmış olsam da, tek sıralı söz dizimi hakkında bilgi sahibi oldum). İşte bu yüzden, kodun altındaki metinde, neyin presidence olduğunu açıklıyorum. Yine de bilgi için teşekkürler. –

cevap

10

Başlamak için, üç orderby numaralı ifadeyi belirtmek yanlış bir fikirdir; bunun yerine virgülle ayırma özelliğini kullanarak birden fazla siparişi belirtin.

Ayrıca sipariş vermek için Randomiser.Next() kullanma fikrine meraklı değilim, ama bu bir yana.

Kişisel LINQ sorgusu (an için de Randomiser ile hala) bu gibi görünmelidir: Şahsen

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

Ben sadece bunun için nokta işaretini kullanmak:

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

sıralamak için yerinde, temelde birden fazla şeyi test edebilen Comparison<T> veya IComparer<T>'a gereksiniminiz vardır, ayrıca özellikleri kullanarak bir karşılaştırma yapan bir uygulama. Sen (Marc'ın kod uyarınca) elle bunu yapabilir, ama olur, ben MiscUtil bazı yardımcı sınıflar ve uzatma yöntemleri var:

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

list.Sort(comparer); 

Not burada Randomizer kullanarak kötü bir fikir kesinlikle olduğunu, olarak her karşılaştırmada (eşit ilk parçalara sahip nesneler için) çağrılacak ... bu, x < z < x gibi bir tutarsız karşılaştırmaya yol açabilir.

+0

Finalde rastgele bir sayı (siparişe göre diğer tüm sıralar eşittir) tarafından bir sipariş vermek için bir seçenek ne olurdu? –

+0

Ayrıca, çoklu okunabilirliğin salt okunabilirlikten dolayı kötü bir fikir mi kullanıyor yoksa başka bir nedeni var mı? –

+0

@George: Temel olarak bu durumda tutarlı bir siparişiniz yok. İki nesneyi tutarlı bir şekilde ayırt edemezseniz, neden onları karşılaştırırken sadece 0 döndürmeyin? –

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; 
}); 

veya benzeri (belki de bir karşılaştırıcısı sınıfında, bu önemsiz olmayan ise).