Acceso directo para crear una lista de elementos individuales en C #


134

En C #, ¿hay un acceso directo en línea para crear una instancia de la Lista <T> con un solo elemento?

Actualmente estoy haciendo:

new List<string>( new string[] { "title" } ))

Tener este código en todas partes reduce la legibilidad. He pensado en usar un método de utilidad como este:

public static List<T> SingleItemList<T>( T value )
{
    return (new List<T>( new T[] { value } ));
}

Entonces podría hacer:

SingleItemList("title");

¿Hay una manera más corta / más limpia?

Gracias.

Respuestas:


245

Simplemente use esto:

List<string> list = new List<string>() { "single value" };

Incluso puede omitir las llaves ():

List<string> list = new List<string> { "single value" };

Actualización: por supuesto, esto también funciona para más de una entrada:

List<string> list = new List<string> { "value1", "value2", ... };

55
poner un 1 literal en los paréntesis de la primera opción, por lo que el almacenamiento durante exactamente un espacio se asigna el valor por defecto en lugar de 10
Joel Coehoorn

55
El valor predeterminado termina siendo 4, creo: nueva Lista <string> {"Hello"} .Capacity == 4
Jon Skeet el

39
var list = new List<string>(1) { "hello" };

Muy similar a lo que otros han publicado, excepto que se asegura de asignar solo espacio para el elemento único inicialmente.

Por supuesto, si sabe que agregará un montón de cosas más tarde, puede que no sea una buena idea, pero vale la pena mencionarlo una vez.


Capacidad establecida en uno. Voté por cuatro respuestas en esta página, incluidas las de Jon Skeet, pero considero que esta es la más correcta.
The Lonely Coder

28

La idea de Michael de usar métodos de extensión conduce a algo aún más simple:

public static List<T> InList<T>(this T item)
{
    return new List<T> { item };
}

Entonces podrías hacer esto:

List<string> foo = "Hello".InList();

No estoy seguro de si me gusta o no, eso sí ...


1
Tampoco estoy seguro de que me guste: ¿no es esta una extensión "extraña" del tipo de cadena (por ejemplo)?
M4N

1
Todavía no he llegado a los métodos de extensión en su libro, Jon :-) Esto parece un poco extraño, pero me gusta su utilidad. Gracias Martin y Jon.
Ryan Ische el

2
@ Martin: Es una extensión extraña de todo tipo. Esto generalmente se desaconseja, pero es una idea general interesante.
Jon Skeet el

44
Tiene algunos usos de lenguaje específicos de dominio interno, especialmente con los tipos de valor. Tomemos, por ejemplo: clock.AlertUser.In (1.Minute) se lee mucho mejor que clock.AlertUser (TimeSpan.FromMinutes (1));
Michael Meadows el

17

Una respuesta diferente a la anterior, basada en la exposición a las Colecciones de Google Java :

public static class Lists
{
    public static List<T> Of<T>(T item)
    {
        return new List<T> { item };
    }
}

Luego:

List<string> x = Lists.Of("Hello");

Aconsejo revisar el GJC - tiene muchas cosas interesantes adentro. (Personalmente ignoraría la etiqueta "alpha" - es solo la versión de código abierto que es "alpha" y se basa en una API interna muy estable y muy utilizada) .)



7

Use un método de extensión con el método de encadenamiento.

public static List<T> WithItems(this List<T> list, params T[] items)
{
    list.AddRange(items);
    return list;
}

Esto te permitiría hacer esto:

List<string> strings = new List<string>().WithItems("Yes");

o

List<string> strings = new List<string>().WithItems("Yes", "No", "Maybe So");

Actualizar

Ahora puede usar inicializadores de lista:

var strings = new List<string> { "This", "That", "The Other" };

Ver http://msdn.microsoft.com/en-us/library/bb384062(v=vs.90).aspx


Tal vez esto se deba a las nuevas versiones de C # desde 2009, pero creo new List<string> {"Yes"}que es mejor ...
ErikE

@ErikE De acuerdo con la documentación de Microsoft ( msdn.microsoft.com/en-us/library/bb384062(v=vs.90).aspx ) esto fue compatible con Visual Studio 2008. No recuerdo tan atrás para decir definitivamente si Complicé demasiado esto en ese momento. Actualizando
Michael Meadows

7

Otra forma más, que se encuentra en "C # /. Net Little maravillas" (desafortunadamente, el sitio ya no existe):

Enumerable.Repeat("value",1).ToList()

Confuso pero inteligente.
PRMan

4

Para un solo elemento enumerable en java sería Collections.singleton ("string");

En c # esto será más eficiente que una nueva Lista:

public class SingleEnumerator<T> : IEnumerable<T>
{
    private readonly T m_Value;

    public SingleEnumerator(T value)
    {
        m_Value = value;
    }

    public IEnumerator<T> GetEnumerator()
    {
        yield return m_Value;
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        yield return m_Value;
    }
}

pero hay una manera más simple de usar el marco?


Esa es realmente la mejor respuesta en mi opinión. Es un patrón muy común tener una sola lista de elementos, para reducir el tamaño de la asignación. Si ya está buscando un atajo, podría combinar lo conveniente con lo bueno.
Alex


2

Tengo esta pequeña función:

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

Como no prescribe un tipo de retorno concreto, es tan genérico que lo uso por todas partes. Tu código se vería así

CoreUtil.ToEnumerable("title").ToList();

Pero, por supuesto, también permite

CoreUtil.ToEnumerable("title1", "title2", "title3").ToArray();

A menudo lo uso cuando tengo que agregar / anteponer un elemento a la salida de una declaración LINQ. Por ejemplo, para agregar un elemento en blanco a una lista de selección:

CoreUtil.ToEnumerable("").Concat(context.TrialTypes.Select(t => t.Name))

Guarda algunos ToList()y Adddeclaraciones.

(Respuesta tardía, pero me topé con este viejo y pensé que esto podría ser útil)



2

Inspirado por las otras respuestas (¡y así puedo recogerlo cuando lo necesite!), Pero con nombres / estilos alineados con F # (que tiene una singletonfunción estándar por estructura de datos *):

namespace System.Collections.Generic
{
    public static class List
    {
        public static List<T> Singleton<T>(T value) => new List<T>(1) { value };
    }
}

* excepto por ResizeArraysí mismo, por supuesto, de ahí esta pregunta :)


En la práctica he hecho nombro Createpara alinearse con otros ayudantes defino como Tuple.Create, Lazy.Create[2], LazyTask.Createetc:

namespace System.Collections.Generic
{
    public static class List
    {
        public static List<T> Create<T>(T value) => new List<T>(1) { value };
    }
}

[2]

namespace System
{
    public static class Lazy
    {
        public static Lazy<T> Create<T>(Func<T> factory) => new Lazy<T>(factory);
    }
}

¡Gracias! Mi solución también. Un par de cosas: (1) la implementación de su lista no es pública, por lo que no se puede usar fuera del conjunto de declaración, y (2) ¿cuál es el propósito de insertar esto en el espacio de nombres del Sistema?
Codure

La razón de @StephenRobinson para colocar la Lazyextensión Systemes que Lazysí está en System[y, por Createlo tanto , aparecería en las listas de complementos sin un using]. ¿No se gana nada forzando a las personas a openun espacio de nombres diff? Hacer que la otra cosa sea privada no fue intencional; corregido
Ruben Bartelink

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.