2010-08-04 17 views
9

Ho bisogno di anteporre un singolo valore a un oggetto IEnumerable (in questo caso, IEnumerable<string[]>). Per fare questo, sto creando un List<T> solo per avvolgere il primo valore in modo che io possa chiamare Concat:Qual è un modo semplice per aggiungere o anteporre un singolo valore a un oggetto IEnumerable <T>?

// get headers and data together 
IEnumerable<string[]> headers = new List<string[]> { 
    GetHeaders() 
}; 
var all = headers.Concat(GetData()); 

Yuck. C'è un modo migliore? E come gestiresti il ​​caso opposto di aggiungere un valore?

risposta

23

ho scritto metodi di estensione personalizzati per fare questo:

public static IEnumerable<T> Append<T>(this IEnumerable<T> source, T item) 
{ 
    foreach (T i in source) 
     yield return i; 

    yield return item; 
} 

public static IEnumerable<T> Prepend<T>(this IEnumerable<T> source, T item) 
{ 
    yield return item; 

    foreach (T i in source) 
     yield return i; 
} 

Nel vostro scenario, si può scrivere:

var all = GetData().Prepend(GetHeaders()); 

Come chilltemp ha commentato, questo non muta la collezione originale. Nella vera moda Linq, genera un nuovo IEnumerable<T>.

Nota: si raccomanda Un ansiosi controllo argomento null per source, ma non mostrato per brevità.

+0

Nice! Ne ho alcuni nella mia biblioteca come quelli. – kbrimington

+3

Elegante. Va notato che ciò restituirà un nuovo IEnumerable enumerando la raccolta esistente. In realtà non aggiunge/antepone la collezione originale. – chilltemp

7

Utilizzare il metodo di estensione Enumerable.Concat. Per aggiungere valori anziché prepending, devi semplicemente chiamare Concat al contrario. (Es: GetData().Concat(GetHeaders());)

Se GetHeaders() restituisce una singola matrice di stringhe, io personalmente probabilmente avvolgerla in un singolo array elemento invece di una lista:

var all = (new[] {GetHeaders()}).Concat(GetData()); 
+0

GetHeaders() restituisce 'string []', GetData() restituisce '' IEnumerable . Hai letto la mia domanda? –

+0

@Gabe: Funzionerà con string [] e IEnumerable - gli array implementano IEnumerable . Se la tua stringa [] è ** stringa **, tuttavia, le cose sono un po 'diverse. La tua domanda non era incredibilmente chiara qui. –

+0

@Reed right, ho commentato prima di dire la tua modifica –

1

Rx contiene il metodo StartWith che antepone il valore alla sequenza. Anche Return può avvolgere il valore come sequenza in modo che possa essere aggiunto tramite Concat.

 var c = new[] {4}; 
     var c1 = c.StartWith(1, 2, 3); 
     var c2 = c1.Concat(EnumerableEx.Return(5)); 

     c2.Run(Console.Write); // 12345 
0

Un'altra opzione è un metodo di supporto che crea una sequenza da un unico elemento:

public static class EnumerableExt 
{ 
    public static IEnumerable<T> One<T>(T item) 
    { 
     yield return item; 
    } 
} 

... 
//prepend: 
EnumerableExt.One(GetHeaders()).Concat(GetData()); 

//append: 
GetData().Concat(EnumerableExt.One(GetHeaders()); 
Problemi correlati