2009-06-13 6 views
9

Ho una raccolta di oggetti di un tipo che mi piacerebbe convertire in un tipo diverso. Questo può essere fatto facilmente con foreach, ma mi piacerebbe capire come usare la funzione di aggregazione di Linq per farlo.Come aggiungere a un elenco utilizzando la funzione di aggregazione di Linq C#

Il problema è che tutti gli esempi di Aggregate utilizzano tipi di stringa di riga o int, che supportano l'operatore '+'. Mi piacerebbe che il tipo di accumulatore fosse una lista, che non supporta la semantica '+'.

Ecco un rapido esempio:

public class DestinationType 
{ 
    public DestinationType(int A, int B, int C) { ... } 
} 

var set = from item in context.Items 
      select new { item.A, item.B, item.C }; 

var newSet = set.Aggregate(new List<DestinationType>(), 
          (list, item) => list.Add(new DestinationType(item.A, item.B, item.C))); 

Il problema è che Lista <> .Add restituisce void. Il tipo di ritorno del secondo parametro in Aggregato deve essere un elenco.

Se avessi un tipo di lista che ha sostenuto '+' di tipo semantica ho potuto solo fare il secondo parametro

list + item 

Tuttavia non posso trovare qualsiasi tipo di raccolta che supporta questo genere di cose.

Sembra che questo dovrebbe essere facilmente possibile in Linq. C'è un modo? Inoltre, se mi manca un modo completamente più semplice, mi piacerebbe conoscere anche questo. Grazie!

+0

Grazie per tutte le grandi risposte! Le risposte di Sam & Talljoe hanno ottenuto questo semplicemente usando Linq. Di nuovo! – Slaggg

risposta

9

Penso che una chiamata a Select combinata con ToList() potrebbe essere quello che ti serve qui. Per esempio:

context.Items 
    .Select(item => new DestinationType(item.A, item.B, item.C)) 
    .ToList(); 
23

assumendo questo è LINQ to Objects, provare ...

var newSet = set.Aggregate(new List<DestinationType>(), 
            (list, item) => 
            { 
             list.Add(new DestinationType(item.A, item.B, item.C)); 
             return list; 
            }); 
+0

Questo è il modo giusto per farlo. – mquander

+0

Questo ha funzionato anche con me quando si utilizza Union nella parte Func –

4

Si può solo applicare select qui.

var newSet = set.Select(item => new DestinationType(...)).ToList(); 

Aggregate (generalmente noto come fold o reduce) viene utilizzato per combinare elementi insieme dove select applica una funzione per ogni elemento.

Es:

Sia f una funzione unaria, allora [a, b, c].select(f) uguale [f(a), f(b), f(c)].

Sia f una funzione binaria, quindi [a, b, c].aggregate(f, init) uguale f(a, f(b, f(c, init))).

Il modo in cui si è scelto nel tuo esempio è raro in C#, ma spesso utilizzato in programmazione funzionale dove (collegate) liste sono trasformate in nuove liste invece di cambiare una raccolta esistente:

reversed = fold (\list element -> element:list) [] [1..10] 

Se davvero si vuole fai questo calcolo con aggregate, usa la soluzione di Dustin o meglio implementa un tipo basato su elenco collegato per collezioni immutabili (puoi anche dare a questo tipo un operator +).

3
list.AddRange(context.Items.Select(item => 
    new DestinationType(item.A, item.B, item.C)); 

Mi rendo conto che non utilizza la funzione di aggregazione, ma probabilmente si dovrebbe trovare un esempio migliore da utilizzare per imparare l'aggregato.

1

A meno che non mi manca qualcosa di ovvio, perché non basta fare:

public class DestinationType 
{ 
    public DestinationType(int A, int B, int C) { ... } 
} 

var newSet = from item in context.Items 
    select new DestinationType(item.A, item.B, item.C); 
Problemi correlati