Scorciatoia per la creazione di un singolo elenco di elementi in C #


134

In C #, esiste un collegamento in linea per creare un'istanza di un Elenco <T> con un solo elemento.

Attualmente sto facendo:

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

Avere questo codice ovunque riduce la leggibilità. Ho pensato di utilizzare un metodo di utilità come questo:

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

Quindi potrei fare:

SingleItemList("title");

C'è un modo più breve / più pulito?

Grazie.

Risposte:


245

Basta usare questo:

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

Puoi anche omettere le parentesi graffe ():

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

Aggiornamento: ovviamente questo funziona anche per più di una voce:

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

5
inserisci 1 letterale tra parentesi della prima opzione, in modo che venga allocato lo spazio di archiviazione esattamente per uno spazio anziché il valore predefinito 10
Joel Coehoorn,

5
Il valore predefinito finisce per essere 4, credo: nuovo Elenco <stringa> {"Ciao"}. Capacità == 4
Jon Skeet

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

Molto simile a quello che altri hanno pubblicato, tranne per il fatto che inizialmente alloca solo lo spazio per il singolo elemento.

Naturalmente, se sai che aggiungerai un sacco di cose in seguito, potrebbe non essere una buona idea, ma vale comunque la pena menzionarle una volta.


La capacità è impostata su uno. Ho votato per quattro risposte su questa pagina, incluse quelle di Jon Skeet, ma ritengo che questa sia la più corretta.
The Lonely Coder,

28

L'idea di Michael di utilizzare i metodi di estensione porta a qualcosa di ancora più semplice:

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

Quindi potresti farlo:

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

Non sono sicuro che mi piaccia o no, intendiamoci ...


1
Inoltre non sono sicuro che mi piaccia: non è questa un'estensione "strana" del tipo di stringa (per esempio)?
M4N,

1
Non ho ancora raggiunto metodi di estensione nel tuo libro, Jon :-) Questo sembra strano, ma mi piace l'utilità. Grazie Martin e Jon.
Ryan Ische,

2
@Martin: è una strana estensione di ogni tipo. Questo è generalmente scoraggiato, ma è un'idea generale interessante.
Jon Skeet,

4
Ha alcuni usi linguistici specifici del dominio interno, specialmente con tipi di valore. Prendiamo ad esempio: clock.AlertUser.In (1.Minute) legge molto meglio di clock.AlertUser (TimeSpan.FromMinutes (1));
Michael Meadows,

17

Una risposta diversa alla mia precedente, basata sull'esposizione alle raccolte Java di Google :

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

Poi:

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

Consiglio di dare un'occhiata al GJC - contiene molte cose interessanti. (Personalmente ignorerei il tag "alpha" - è solo la versione open source che è "alpha" ed è basata su un'API interna molto stabile e molto usata .)


8
new[] { "item" }.ToList();

È più corto di

new List<string> { "item" };

e non è necessario specificare il tipo.


7

Utilizzare un metodo di estensione con concatenamento di metodi.

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

Questo ti permetterebbe di fare questo:

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

o

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

Aggiornare

Ora puoi utilizzare gli inizializzatori di elenchi:

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

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


Forse questo è dovuto alle versioni più recenti di C # dal 2009, ma trovo new List<string> {"Yes"}che sia migliore ...?
ErikE,

@ErikE Secondo la documentazione Microsoft ( msdn.microsoft.com/en-us/library/bb384062(v=vs.90).aspx ) questo è stato supportato in Visual Studio 2008. Non ricordo che molto tempo fa dire definitivamente se L'ho complicato troppo al momento. In aggiornamento.
Michael Meadows,

7

Ancora un altro modo, trovato su "C # /. Net Little Wonders" (sfortunatamente, il sito non esiste più):

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

Confuso ma intelligente.
PRMan,

4

Per un singolo elemento enumerabile in java sarebbe Collections.singleton ("stringa");

In c # questo sarà più efficiente di un nuovo elenco:

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;
    }
}

ma c'è un modo più semplice di usare il framework?


Questa è in realtà la migliore risposta secondo me. È un modello molto comune avere un unico elenco di articoli, per ridurre le dimensioni dell'allocazione. Se stai già cercando una scorciatoia, potresti anche combinare il comodo con il buono.
Alex


2

Ho questa piccola funzione:

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

Dal momento che non prescrive un tipo di ritorno concreto, questo è così generico che lo uso ovunque. Il tuo codice sarebbe simile

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

Ma ovviamente lo permette anche

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

Lo uso spesso quando devo aggiungere / anteporre un elemento all'output di un'istruzione LINQ. Ad esempio per aggiungere un elemento vuoto a un elenco di selezione:

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

Salva alcune dichiarazioni ToList()e Add.

(Risposta tardiva, ma mi sono imbattuto in questo vecchio e ho pensato che potesse essere utile)



2

Ispirato dalle altre risposte (e quindi posso raccoglierlo ogni volta che ne ho bisogno!), Ma con denominazione / stile allineati con F # (che ha una singletonfunzione standard per struttura di dati *):

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

* tranne che per ResizeArraysé ovviamente, quindi questa domanda :)


In pratica lo chiamo in realtàCreate per allinearlo con altri helper che definisco come Tuple.Create, Lazy.Create[2], LazyTask.Createecc:

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);
    }
}

Grazie! Anche la mia soluzione. Un paio di cose: (1) l'implementazione della tua lista non è pubblica, quindi non può essere usata al di fuori dell'assembly dichiarante, e (2) qual è lo scopo di inserirle nello spazio dei nomi di sistema?
Codure del

La ragione di @StephenRobinson per inserire l' Lazyestensione Systemè che Lazysi trova in System[e quindi Createapparirebbe negli elenchi di compleiton senza un using]. Non c'è niente da guadagnare dal forzare le persone a openuno spazio dei nomi diff? Rendere l'altra cosa privata non era intenzionale; risolto
Ruben Bartelink il

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.