2011-02-03 10 views
39

Básicamente estoy tratando de hacer algo como esto:¿Hay un método de Linq para agregar un solo elemento a un IEnumerable <T>?

image.Layers 

que devuelve un IEnumerable para todas las capas excepto la capa Parent, pero en algunos casos, sólo quiero hacer:

image.Layers.With(image.ParentLayer); 

porque solo se usa en algunos lugares en comparación con los 100 del uso habitual que se cumple con image.Layers. Es por eso que no quiero hacer otra propiedad que también devuelva la capa Parent.

+0

https://github.com/morelinq/MoreLINQ#concat apoya esto. https://www.nuget.org/packages/morelinq/ – mjwills

Respuesta

41

Una forma sería la creación de un conjunto unitario-secuencia fuera del elemento (como una matriz), y luego Concat que en el original:

image.Layers.Concat(new[] { image.ParentLayer }) 

Si usted está haciendo esto muy a menudo, considere escribir una extensión método Append (o similar), como el que se listed here, que le permiten hacer:

image.Layers.Append(image.ParentLayer) 
+1

MSFT Conectar sugerencia aquí: http://bit.ly/lpcWjU –

+0

@IanMercer La sugerencia ha caducado. – McKay

7

Puede utilizar Enumerable.Concat:

var allLayers = image.Layers.Concat(new[] {image.ParentLayer}); 
1

No es el método Concat que une dos secuencias.

+3

El segundo elemento no es una secuencia ... ese es el punto de la pregunta. – nicodemus13

5

usted puede hacer algo como:

image.Layers.Concat(new[] { image.ParentLayer }); 

cuales concats la enumeración de una serie de un solo elemento que contiene la cosa que desea añadir

2

Si te gusta la sintaxis de .Con, escribo como un método de extensión. IEnumerable no notará otro.

11

No hay un solo método que lo haga. El más cercano es el método Enumerable.Concat pero que intenta combinar un IEnumerable<T> con otro IEnumerable<T>. Se puede utilizar el siguiente para que funcione con un solo elemento

image.Layers.Concat(new [] { image.ParentLayer }); 

O simplemente añadir un nuevo método de extensión

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

vez que hice una pequeña función agradable para esto:

public static class CoreUtil 
{  
    public static IEnumerable<T> AsEnumerable<T>(params T[] items) 
    { 
     return items; 
    } 
} 

Ahora esto es posible:

image.Layers.Append(CoreUtil.AsEnumerable(image.ParentLayer, image.AnotherLayer)) 
+1

'AsEnumerable' es ahora [a método de extensión incorporada] (http://msdn.microsoft.com/en-us/library/vstudio/bb335435%28v=vs.100%29.aspx) como de .Net 3.5 , por lo que un nombre diferente podría estar en orden. Además, 'AsX' implica que es un método de extensión (¿no se supone que los métodos son un verbo?), Así que no creo que fuera un buen nombre en primer lugar. Sugeriría 'Enumerate'. – ErikE

+0

¡Ja! Hace mucho tiempo. Sí, llegué a la misma conclusión mientras tanto. Aún uso la pequeña cosa, pero ahora es 'ToEnumerable'. 'Enumerate' tampoco está mal. –

+0

Todavía veo 'ToEnumerable' como sugiriendo un método de extensión. ¿Qué tal 'CreateEnumerable'? :) – ErikE

24

Muchas implementaciones ya se han dado. El mío se ve un poco diferente (pero funciona igual de bien)

Además, me parece práctico tener también control sobre el PEDIDO. así que a menudo, también tengo un método ConcatTo, poniendo el nuevo elemento op en primer plano.

public static class Utility 
{ 
    /// <summary> 
    /// Adds the specified element at the end of the IEnummerable. 
    /// </summary> 
    /// <typeparam name="T">The type of elements the IEnumerable contans.</typeparam> 
    /// <param name="target">The target.</param> 
    /// <param name="item">The item to be concatenated.</param> 
    /// <returns>An IEnumerable, enumerating first the items in the existing enumerable</returns> 
    public static IEnumerable<T> ConcatItem<T>(this IEnumerable<T> target, T item) 
    { 
     if (null == target) throw new ArgumentException(nameof(target)); 
     foreach (T t in target) yield return t; 
     yield return item; 
    } 

    /// <summary> 
    /// Inserts the specified element at the start of the IEnumerable. 
    /// </summary> 
    /// <typeparam name="T">The type of elements the IEnumerable contans.</typeparam> 
    /// <param name="target">The IEnummerable.</param> 
    /// <param name="item">The item to be concatenated.</param> 
    /// <returns>An IEnumerable, enumerating first the target elements, and then the new element.</returns> 
    public static IEnumerable<T> ConcatTo<T>(this IEnumerable<T> target, T item) 
    { 
     if (null == target) throw new ArgumentException(nameof(target)); 
     yield return item; 
     foreach (T t in target) yield return t; 
    } 
} 

O, alternativamente, utilizar una matriz creado implícitamente.(Utilizando los params palabra clave) para que pueda llamar al método para agregar uno o más elementos a la vez:

public static class Utility 
{ 
    /// <summary> 
    /// Adds the specified element at the end of the IEnummerable. 
    /// </summary> 
    /// <typeparam name="T">The type of elements the IEnumerable contans.</typeparam> 
    /// <param name="target">The target.</param> 
    /// <param name="items">The items to be concatenated.</param> 
    /// <returns>An IEnumerable, enumerating first the items in the existing enumerable</returns> 
    public static IEnumerable<T> ConcatItems<T>(this IEnumerable<T> target, params T[] items) => 
     (target ?? throw new ArgumentException(nameof(target))).Concat(items); 

    /// <summary> 
    /// Inserts the specified element at the start of the IEnumerable. 
    /// </summary> 
    /// <typeparam name="T">The type of elements the IEnumerable contans.</typeparam> 
    /// <param name="target">The IEnummerable.</param> 
    /// <param name="items">The items to be concatenated.</param> 
    /// <returns>An IEnumerable, enumerating first the target elements, and then the new elements.</returns> 
    public static IEnumerable<T> ConcatTo<T>(this IEnumerable<T> target, params T[] items) => 
     items.Concat(target ?? throw new ArgumentException(nameof(target))); 
+0

Por lo general, no me gusta ver los mensajes antiguos chocaban mi página de inicio como este, pero me gusta bastante su solución :) – Rawling

+2

1 para proporcionar la respuesta que no lo hace innecesario asignar una nueva lista a concat un solo elemento. ¡Y proporciona más flexibilidad en eso! – KChaloux

+1

.NET probablemente compilará la sentencia de rendimiento en un objeto anónimo, que se instanciará. –

3

que utilizan los siguientes métodos de extensión para evitar crear un inútil Array:

public static IEnumerable<T> ConcatSingle<T>(this IEnumerable<T> enumerable, T value) { 
    return enumerable.Concat(value.Yield()); 
} 

public static IEnumerable<T> Yield<T>(this T item) { 
    yield return item; 
} 
+0

+1 Buena implementación, pero ¿por qué evitar la matriz? Sé que se siente mal crear la matriz, pero ¿es realmente menos eficiente que todo el trabajo oculto que hace C# para estos iteradores? – dss539

+1

Buena pregunta, no he referenciado se ... –

+1

Rendimiento asignará y devolver un IEnumerable anónima que contiene una referencia a su artículo, por lo que probablemente tiene más memoria y tiempo que la matriz solo artículo. –

0
/// <summary>Concatenates elements to a sequence.</summary> 
/// <typeparam name="T">The type of the elements of the input sequences.</typeparam> 
/// <param name="target">The sequence to concatenate.</param> 
/// <param name="items">The items to concatenate to the sequence.</param> 
public static IEnumerable<T> ConcatItems<T>(this IEnumerable<T> target, params T[] items) 
{ 
    if (items == null) 
     items = new [] { default(T) }; 
    return target.Concat(items); 
} 

Esta solución se basa en realbart's answer. Me ajusté para permitir el uso de un único valor null como parámetro:

var newCollection = collection.ConcatItems(null) 
Cuestiones relacionadas