2009-04-29 7 views
16

Por ejemplo:¿Hay una declaración a anteponer un elemento T a un IEnumerable <T>

string element = 'a'; 
IEnumerable<string> list = new List<string>{ 'b', 'c', 'd' }; 

IEnumerable<string> singleList = ???; //singleList yields 'a', 'b', 'c', 'd' 
+0

En .NET Core es una función de: '' '' public static System.Collections.Generic.IEnumerable Anteponer (esto System.Collections.Generic.IEnumerable fuente, elemento TSource); '' '' (https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.prepend?view=netcore-2.0) –

+0

Y como parte de la implementación .Net Standard 2.0, está incluido en .Net 4.7.1. – NetMage

Respuesta

28

¿Puedo entender que pueda no sólo Insert en la lista existente?

Bueno, podría usar new[] {element}.Concat(list).

De lo contrario, se podría escribir su propio método de extensión:

public static IEnumerable<T> Prepend<T>(
      this IEnumerable<T> values, T value) { 
     yield return value; 
     foreach (T item in values) { 
      yield return item; 
     } 
    } 
    ... 

    var singleList = list.Prepend("a"); 
+6

+1. Pero :(para los corchetes de estilo Java! –

+6

@Ian: Creo que te refieres a The One True Brace Style, de K & R en adelante. – Richard

+0

¿No debería ser Concat() en lugar de Union()? Union() solo devuelve elementos distintos. – Lucas

1

No, no hay tal incorporado DECLARACIÓN, declaración, pero es trivial para implementar dicha función:

IEnumerable<T> PrependTo<T>(IEnumerable<T> underlyingEnumerable, params T[] values) 
{ 
    foreach(T value in values) 
     yield return value; 

    foreach(T value in underlyingEnumerable) 
     yield return value; 
} 

IEnumerable<string> singleList = PrependTo(list, element); 

Puede incluso conviértalo en un método de extensión si la versión de C# lo permite.

+0

Si hace esto un método de extensión, acaba de implementar IEnumerable .Union(): P – Lucas

+1

errr me refiero a Concat() – Lucas

5

Puede rodar su propia:

static IEnumerable<T> Prepend<T>(this IEnumerable<T> seq, T val) { 
yield return val; 
foreach (T t in seq) { 
    yield return t; 
} 
} 

y luego usarlo:

IEnumerable<string> singleList = list.Prepend(element); 
+2

Creo que debería ser "yield return t" dentro del foreach y el método debe ser estático –

4
public static class IEnumerableExtensions 
{ 
    public static IEnumerable<T> Prepend<T>(this IEnumerable<T> ie, T item) 
    { 
     return new T[] { item }.Concat(ie); 
    } 
} 
+0

Parece que me gusta que está haciendo coincidir el elemento hasta el final, no anteponiéndolo ... –

+0

Vaya, buen punto. Editaré ... – BFree

3

Esto lo haría ...

IEnumerable<string> singleList = new[] {element}.Concat(list); 

Si quería la SingleList para ser una lista, entonces ...

IEnumerable<string> singleList = new List<string>() {element}.Concat(list); 

... funciona también.

+0

En su segundo ejemplo, SingleList es un IEnumerable, no una lista. – Lucas

+0

Se arregló para Martin. – NetMage

+0

Pero fue rechazado. ¿No deberían los editores tener un estándar más alto aquí, como ser capaces de comprender el código? – NetMage

3

también:

IEnumerable<string> items = Enumerable.Repeat(item, 1).Concat(list); 
1

Me resulta conveniente para poder anteponer varios elementos de una manera chainable. Esta versión aprovecha los métodos de extensión y params.

Como nota, esta versión permite implícitamente null, pero es tan fácil cambiarla a throw new NullReferenceException() si ese es el comportamiento deseado.

public static class IEnumerableExtensions 
{ 
    public static IEnumerable<T> Prepend<T>(this IEnumerable<T> source, params T[] items) 
    { 
     return items.Concat(source ?? new T[0]); 
    } 
} 

permite una sintaxis muy legible para los artículos individuales:

GetItems().Prepend(first, second, third); 

... y para colecciones de artículos:

GetItems().Prepend(GetMoreItems()); 

acabado el ejemplo de los resultados de la pregunta en:

string element = "a"; 
IEnumerable<string> list = new List<string>{ "b", "c", "d" }; 

IEnumerable<string> singleList = list.Prepend(element); 
+1

Parece que tiene un error tipográfico en el que hace referencia 'fuente' pero declara' fuentes'? – NetMage

+0

@NetMage, gracias por atrapar eso. – zzzzBov

+0

No hay problema, este es mi favorito de 'Prepend' - lamentablemente no es lo que se agregó .Net Core y .Net Standard 2.0. – NetMage

0

Solo como un recordatorio - Lista < T> no es el único tipo de contenedor. Si se encuentra agregando elementos al frente de la lista con bastante frecuencia, también puede considerar usar Pila < T> para implementar su contenedor.Una vez que tenga una pila

var container = new Stack<string>(new string[] { "b", "c", "d" }); 

siempre se puede "anteponer" un elemento a través

container.Push("a"); 

y seguir utilizando la colección como IEnumerable < T> como en

foreach (var s in container) 
    // do sth with s 

además todos los otros métodos típicos para una pila como Pop(), Peek(), ...

Algunas de las soluciones anteriores se repiten en todo el IEnumeration < T> solo para anteponer un elemento (o más de uno en uno). Esta puede ser una operación muy costosa si su colección contiene una gran cantidad de elementos y la frecuencia de antemano es relativamente alta.

0

Al mirar algunos de los ejemplos, creo que preferiría invertir la extensión para aplicarla al objeto.

public static IEnumerable<T> PrependTo<T>(this T value, IEnumerable<T> values) { 
    return new[] { value }.Concat(values); 
} 

utilizado como

var singleList = element.PrependTo(list); 
Cuestiones relacionadas