2009-03-12 10 views
16

posso appiattire i risultati di una collezione bambino all'interno di una collezione con SelectMany:SelectMany tre livelli profondi

// a list of Foos, a Foo contains a List of Bars 
var source = new List<Foo>() { ... }; 

var q = source.SelectMany(foo => foo.Bar) 
    .Select(bar => bar.barId) 
.ToList(); 

questo mi dà la lista di tutti i Bar Ids nella lista Foo. Quando provo ad andare su tre livelli, viene restituito il risultato errato.

var q = source.SelectMany(foo => foo.Bar) 
    .SelectMany(bar => bar.Widget) 
     .Select(widget => widget.WidgetId) 
.ToList(); 

Come dovrei usare SelectMany per ottenere l'elenco di tutti i widget in tutti i bar nella mia lista dei Foos?

Modifica Ho sbagliato la frase sopra, ma il codice riflette l'obiettivo. Sto cercando un elenco di tutti gli ID widget, non i widget.

Un risultato "errato" non è tutti gli ID del widget restituiti.

+0

sembra OK per me. "il risultato errato viene restituito" non è un messaggio di errore descrittivo, cosa ottieni e cosa ti aspetti? – erikkallen

risposta

30

La query restituisce tutti gli ID del widget, anziché tutti i widget. Se si desidera solo i widget, basta usare:

var q = source.SelectMany(foo => foo.Bar) 
       .SelectMany(bar => bar.Widget) 
       .ToList(); 

se questo è ancora dare "il risultato non corretto" si prega di spiegare in che modo è il risultato errato. Codice di esempio sarebbe molto utile :)

EDIT: Okay, se si desidera che gli ID dei widget, il codice originale dovrebbe andare bene:

var q = source.SelectMany(foo => foo.Bar) 
       .SelectMany(bar => bar.Widget) 
       .Select(widget => widget.WidgetId) 
       .ToList(); 

che potrebbe anche essere scritto come

var q = (from foo in source 
     from bar in foo.Bar 
     from widget in bar.Widget 
     select widgetId).ToList(); 

se ti piace il formato di espressione della query.

Questo dovrebbe funzionare: se è non funzionante, ciò suggerisce che c'è qualcosa di sbagliato nei dati.

Avremmo dovuto controllare prima - questo è solo LINQ to Objects, o un fornitore più elaborato (ad esempio LINQ to SQL)?

+1

Sì, intendevo dire tutti gli ID dei widget, non i widget restituiti. Quando eseguo il chain SelectMany (...). SelectMany (...). Select() l'ultima selezione non restituisce l'elenco di tutti gli Id dei widget per qualche motivo. – blu

+0

Il suo LINQ-to-Objects. Ok, se la query è accurata in termini di come mi aspetto che funzioni, posso limitare il problema ai dati e andare da lì, grazie. – blu

2
var q = (
    from f in foo 
    from b in f.Bars 
    from w in b.Widgets 
    select w.WidgetId 
    ).ToList(); 

Si noti inoltre che se si desidera che la lista unica, si può fare .Distinct(). ToList(), invece.

+0

Questo presuppone una singola barra per Foo e un singolo Widget per barra. –

+0

@ Jon ma non è esattamente quello che sta facendo? – eglasius

+0

No. Sta selezionando più barre per Foo - questo è ciò che SelectMany fa. –

1
 var q = source.SelectMany(foo => foo.Bar) 
      .SelectMany(bar => bar.Widget,(bar,widget) => widget.WidgetId) 
      .ToList(); 

possiamo chiamare questo sovraccarico di SelectMany() con ci permettono di specificare la proiezione utilizzando lambda experession

+0

qui finiamo per chiamare tre metodi invece di quattro –