nasıl

2015-12-11 7 views
10

sipariş dayalı sıralamak için bennasıl

items : [{id:1,...}, {id:2,...}, {id:3,...}] 

çizelgesine ve var Diyelim sipariş: [2, 3, 1] olsun ben olmasını bekliyoruz enumerable

items : [{id:2,...}, {id:3,...}, {id:1,...}] 

Ancak bir şey daha temiz bir çözüm var mı?


ben bu doğrulama testi için oldu, o işi (HimBromBeere, Domysee, qxg)

var expectedOrder = ordering.Select(x => result.First(o => o.Id == x)); 
var expectedOrder = result.OrderBy(item => Array.FindIndex(ordering,i => i == item.Id)); 
var expectedOrder = result.OrderBy(item => ordering.ToList().FindIndex(i => i == item.Id)); 
var expectedOrder = 
    from o in ordering 
    join i in result 
    on o equals i.Id 
    select i; 

FWI doğruladıktan takiben:

sanırım böyle
[Test] 
    [TestCase(1, 2, 3)] 
    [TestCase(1, 3, 2)] 
    [TestCase(2, 1, 3)] 
    [TestCase(2, 3, 1)] 
    [TestCase(3, 1, 2)] 
    public void Test_Should_Fail_If_GetMessages_Does_Not_Return_Sorted_By_Sent_Then_By_Id_Result(params int[] ordering) 
    { 
     var questions = GetQuestionsData();      
     Mock.Get(_questionService) 
      .Setup(o => o.GetQuestions()) 
      .Returns(questions); 
     var result = _mailboxService.GetMessages();  
     var expectedOrder = ordering.Select(x => result.First(o => o.Id == x)); 

     // Act 
     Action sortOrder =() => expectedOrder.Should() 
      .BeInDescendingOrder(o => o.Sent) 
      .And.BeInDescendingOrder(o => o.Id); 

     // Assert 
     sortOrder.ShouldThrow<AssertionException>(); 
    } 
+0

Kodu daha okunaklı hale getirmek için birleşim kullanmak daha iyi olabilir.Ayrıca i ++ artık gerekli olmadığından biraz daha güvenli olabilir. – momar

+0

Ne kadar temizsiniz? Mevcut çözüm kötü değil. – qxg

+0

Sadece açık olmak gerekirse, onları istediğiniz sırayla 1 tabanlı dizinlerin veya ids listesinin bir listesini 'sipariş etmek'? Çünkü, bir kimlik listesine sahip olursunuz. Bu, bir örnek (yani, bu örnekle eşleşen) kimliğinin bir listesini alır, ancak geçerli kod, aslında 'siparişte' bir değer aramak için kimliği kullanmaz. – juharr

cevap

3

şey :

var result = ordering.Select(x => items.First(y => y.id == x.id)); 

Çalışma örneği:

var items = new[] { new { id = 1, name = "1" }, new { id = 2, name = "2" }, new { id = 3, name = "3" }, new { id = 4, name = "4" } }; 
var result = new[] { 2, 3, 1 }.Select(x => items.First(y => y.id == x)); 

Bu aynı zamanda kimin endeks ordering içinde yer almayan bu items out, filtreler.

+0

OP şu anda "sipariş" içindeki sipariş değerini aramak için 'id' kullanmıyor. 'I ++ 'kullanımı,' siparişin 'ids değil, dizinlerin bir listesi olduğunu gösterir. Örnek, bunun bir kimlik listesi listesiyle eşleşmesiyle olur. – juharr

3

Değişikliklerin bir örnek yakalanan i değişkeni ortadan kaldırır, çünkü yerine

items.Select((o,i) => new {key = ordering[i+1], value = o}) 
    .OrderBy(k => k.key) 
    .Select(o => o.value); 

Bu daha iyi olur size endeksi verir Select aşırı yüklenmesini kullanabilirsiniz.

2

ordering bir List ise, bunu yapabilirsiniz:

items.OrderBy(item => ordering.FindIndex(i => i == item.id)) 
+0

Kimlikler bu şekilde eşleşirken, "sipariş verme" nin aslında dizinlerin değil, dizinlerin bir listesi olduğunu tahmin ediyorum. – juharr

+0

@juharr oh, bu durumda çözümüm yanlış olur. OP'nin buna açık olup olmadığını görelim. – Domysee

2

tek gelişme tekrar dokunun veya yeni nesne düzeni ihtiyacı olmadığını, ancak esasen orijinal kod ile aynıdır.

var query = from o in ordering 
      join i in items 
       on o equals i.Id 
      select i; 
3

kimliklerinizi ardışık ise her dizin için kontrol altında tutabilmek amacıyla diziyi yeniden düzenleyebilirsiniz - Pozisyon sonuç dizide aynı endekse sahip kimliği. Bu böyle yapılabilir:

items = items.OrderBy(x => order[x.Id - 1]); 

Not olduğunu ilk etapta bu şekilde sipariş dizi temsil olsaydı, ilk:

Şimdi
int[] order = new[] {2, 3, 1}; 

order = Enumerable.Range(1, order.Length) 
    .OrderBy(x => order[x - 1]) 
    .ToArray(); 

//Now order = { 3, 1, 2 } which are the one-based indices of each position in the original order array. 

sadece o sonuç dizisi kullanarak sizin Enumerable sipariş edebilirsiniz Linq gereksiz olacağını ve hiçbir gereksiz tekrarlamalar varsa veya bu şekilde Teklif sunması Linq s:

int[] order = new[] {3, 1, 2}; //1 is third, 2 is first, 3 is second. 

items = items.OrderBy(x => order[x.Id - 1]);