2016-02-11 14 views
7

Basicly co próbuję zrobić, to coraz rodzica spis Parent.type gdzie ich Child.type ma status „y” uporządkowane według child.DateLINQ grupa przez dominującego porządku nieruchomości przez dziecko

Jako przykład ja utworzono te klasy:

public class Collection 
{ 
    public IEnumerable<Parent> Parents { get; set; } 
    public int Id { get; set; } 
} 

public class Parent 
{ 
    public int Id { get; set; } 
    public Type type { get; set; }  
    public IEnumerable<Child> Children { get; set; } 
} 

public class Child 
{ 
    public int Id { get; set; } 
    public Status Status { get; set; } 
    public DateTime Date { get; set; } 
} 

public enum Type 
{ 
    a, 
    b 
} 

public enum Status 
{ 
    x, 
    y 
} 

Czego chcę, to lista Rodziców każdego typu, w którym Data Dziecka ma najwyższą wartość.

Aby uzyskać ten przykład dzieje dodałem trochę danych testowych:

Collection collection= new Collection 
     { 
      Id = 1, 
      Parents = new List<Parent> 
      { 
       new Parent 
       { 
        Id= 1, 
        type = Type.a, 
        Children = new List<Child> 
        { 
         new Child 
         { 
          Id = 1, 
          Status = Status.y, 
          Date = DateTime.Now.AddDays(-1) 
         }, 
         new Child 
         { 
          Id = 2, 
          Status = Status.x, 
          Date = DateTime.Now.AddDays(-1) 
         } 
        } 
       }, 
       new Parent 
       { 
        Id= 2, 
        type = Type.b, 
        Children = new List<Child> 
        { 
         new Child 
         { 
          Id = 3, 
          Status = Status.y, 
          Date = DateTime.Now.AddDays(-2) 
         }, 
         new Child 
         { 
          Id = 4, 
          Status = Status.x, 
          Date = DateTime.Now.AddDays(-2) 
         } 
        } 
       }, 
       new Parent 
       { 
        Id= 3, 
        type = Type.a, 
        Children = new List<Child> 
        { 
         new Child 
         { 
          Id = 5, 
          Status = Status.y, 
          Date = DateTime.Now.AddDays(-3) 
         } 
        } 
       }, 
       new Parent 
       { 
        Id= 4, 
        type = Type.b, 
        Children = new List<Child> 
        { 
         new Child 
         { 
          Id = 6, 
          Status = Status.y, 
          Date = DateTime.Now.AddDays(-3) 
         }, 
         new Child 
         { 
          Id = 7, 
          Status = Status.y, 
          Date = DateTime.Now.AddDays(-4) 
         }, 
         new Child 
         { 
          Id = 8, 
          Status = Status.x, 
          Date = DateTime.Now.AddDays(-4) 
         } 
        } 
       }, 
      } 
     }; 

Wynik select powinna być lista zawierająca 2 rodziców. Jeden dla każdego typu (aib). Oba nadal zawierają wszystkie swoje obiekty podrzędne.

Czy jest jakieś proste rozwiązanie?

Próbowałem coś takiego:

List<Parent> test = collection.Parents 
       .GroupBy(m => m.type) 
       .Select(
       m => m.OrderByDescending(
        mm => mm.Children.Select(
         r => r).OrderByDescending(
          r => r.Date)).FirstOrDefault()).ToList(); 

Ale to nie kończy się dobrze.

===== UPDATE =====

Dzięki przykładzie Enigmativity ten problem został rozwiązany. Wprowadziłem niewielką modyfikację zapytania linq, ponieważ oryginalna zawartość, której używam, jest dostarczana przez Entity Framework (6). Oznaczało to dla mnie, że wybrany obiekt nadrzędny nie zawierał żadnych elementów potomnych, więc musiałem wybrać nowy typ obiektu (ponieważ nie można utworzyć nowego obiektu typu udostępnionego przez model Entity Framework). Również moi Rodzice byli w innym IEnumerable, więc musiałem użyć SelectMany również na Rodzicach.

Spowodowało to mniej więcej tak: (To nie będzie działać z klas testowych chociaż)

var result = 
    collection 
     .SelectMany(c => c.Parents) 
     .GroupBy(p => p.type) 
     .SelectMany(gps => 
      gps 
       .SelectMany(
        gp => gp.Children.Where(c => c.Status == Status.y), 
        (gp, c) => new { gp, c }) 
       .OrderByDescending(gpc => gpc.c.Date) 
       .Take(1) 
       .Select(gpc => new ParentData {Id = gpc.gp.Id, Children= gpc.gp.Children})) 
     .ToList(); 
+1

Brawo za przybycie tak nowy i prosząc tak szczegółowe pytanie o kodzie compilable. Dwie szybkie kopie i pasty i udało mi się uruchomić twój kod. Chciałbym, aby więcej nowych użytkowników było równie dobrych. – Enigmativity

Odpowiedz

1

Jeśli mam rozumieć swoje wymagania poprawnie chcesz grupie wszystkich rodziców ze względu na rodzaj, a następnie wybrali tylko jedno z rodziców z każdej grupy na podstawie tego rodzica posiadającego dziecko z najwyższą datą ze wszystkich dzieci w tej grupie.

Oto co wymyśliłem:

var result = 
    collection 
     .Parents 
     .GroupBy(p => p.type) 
     .SelectMany(gps => 
      gps 
       .SelectMany(
        gp => gp.Children.Where(c => c.Status == Status.y), 
        (gp, c) => new { gp, c }) 
       .OrderByDescending(gpc => gpc.c.Date) 
       .Take(1) 
       .Select(gpc => gpc.gp)) 
     .ToList(); 

który daje mi:

result

+0

"staram się uzyskać grupę macierzystą pogrupowaną według Parent.type, gdzie ich Child.type ma status" y "uporządkowany przez child.Date". Nie widzę tego w twoich wynikach – mariovalens

+0

@mariovalens - naprawiono. – Enigmativity

+0

nadal nie tak. On chce wszystkie dzieci ze statusem y. Wybieramy tylko dzieci ze statusem y dla wybranego rodzica. To, czego naprawdę chce, to to, co napisałem w mojej odpowiedzi, by zwinąć rodziców według typu i zsumować wszystkie dzieci dla tego typu statusu y. – mariovalens

0

Dzieci naprawdę nie można być filtrowane, nakazał, itd., Gdy rodzice są tymi, że zapytania/są stosowane projekcje.

Musisz albo:

  • Break relacje i projekt do innej struktury danych (jak słownika lub IGrouping gdzie rodzic jest kluczem, a dzieci są sortowane wartość)
  • koniecznie Sort() lub przypisanie Children w pętli bez LINQ
  • zapisu lambdy wielu linii, gdzie druga linia jest efektem ubocznym jak sortowania lub przypisanie dzieci (niezalecane)

Osobiście uważam, że łatwiej jest wyświetlać tylko te dane, które są potrzebne, do uproszczonej reprezentacji, zamiast próbować utrzymywać hierarchię w dół.

0

Moje rozumienie pytania polega na tym, że należy utworzyć listę rodziców pogrupowanych według rodzaju i zagregować wszystkie dzieci o statusie y dla każdego typu rodzica.

Należy zauważyć, że nie można zwinąć listy według typu nadrzędnego i zachować strukturę macierzystą (co oznacza, że ​​identyfikator również musi zostać zwinięty, właśnie wzięłam pierwszą wartość, wybór zależy od ciebie) .W przeciwnym razie to powinno być rozwiązaniem szukasz:

var result = collection.Parents.GroupBy(c => c.type) 
    .Select(g => new Parent 
       { 
        type = g.Key,  
        Id = g.Select(p => p.Id).FirstOrDefault(), 
        Children = g.SelectMany(p => p.Children 
           .Where(c => c.Status == Status.y) 
           .OrderByDescending(c => c.Date)).ToList()       
       }).ToList(); 
+0

Czy mogę uzyskać powód, dla którego odpowiedź została odrzucona? – mariovalens

+0

"Oba z nich nadal zawierają wszystkie ich obiekty podrzędne." - Twój kod tworzy nowych rodziców i zapełnia je nieprawidłowymi dziećmi. – Enigmativity

+0

Enigmativity, czy próbowałeś uruchomić zapytanie, aby zobaczyć, czy dzieci mają rację? Oczekuje on wszystkich dzieci o statusie "Y", to właśnie autor rozumie przez "wszystkie obiekty potomne". Tak, zapytanie tworzy nowych Rodziców i wyjaśniłem, dlaczego tak jest, i nie jest powiedziane, że wymaga on tych samych obiektów nadrzędnych. – mariovalens