Atalho para criar lista de itens únicos em C #


134

Em C #, existe um atalho embutido para instanciar uma Lista <T> com apenas um item.

Atualmente estou fazendo:

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

Ter esse código em qualquer lugar reduz a legibilidade. Eu pensei em usar um método utilitário como este:

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

Então eu poderia fazer:

SingleItemList("title");

Existe uma maneira mais curta / limpa?

Obrigado.

Respostas:


245

Simplesmente use isto:

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

Você pode até omitir as chaves ():

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

Atualização: é claro que isso também funciona para mais de uma entrada:

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

5
colocar um 1 literal nos parênteses da primeira opção, de modo que o armazenamento para exatamente um espaço é alocado em vez do padrão 10
Joel Coehoorn

5
O padrão acaba sendo 4, acredito: new List <string> {"Hello"} .Capacity == 4
Jon Skeet

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

Muito parecido com o que os outros postaram, exceto pelo fato de alocar espaço para o item único inicialmente.

Obviamente, se você souber que irá adicionar muitas coisas mais tarde, pode não ser uma boa ideia, mas ainda vale a pena mencionar uma vez.


Capacidade definida como um. Votei em quatro respostas nesta página, incluindo as de Jon Skeet, mas considero esta a mais correta.
The Lonely Coder

28

A ideia de Michael de usar métodos de extensão leva a algo ainda mais simples:

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

Então você pode fazer isso:

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

Não sei se gostei ou não, lembre-se ...


1
Também não tenho certeza se gosto: não é uma extensão "estranha" do tipo de string (por exemplo)?
M4N

1
Ainda não fiz métodos de extensão em seu livro, Jon :-) Isso parece meio estranho, mas eu gosto da utilidade disso. Obrigado Martin e Jon.
Ryan Ische

2
@ Martin: É uma extensão estranha de todos os tipos. Isso geralmente é desencorajado, mas é uma ideia geral interessante.
Jon Skeet

4
Ele possui alguns usos de idioma específico do domínio interno, especialmente com tipos de valor. Tomemos, por exemplo: clock.AlertUser.In (1.Minute) lê muito melhor que clock.AlertUser (TimeSpan.FromMinutes (1));
22611 Michael Meadows

17

Uma resposta diferente da anterior, com base na exposição às coleções do Google Java :

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

Então:

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

Aconselho verificar o GJC - ele tem muitas coisas interessantes. (Pessoalmente, eu ignoraria a tag "alpha" - é apenas a versão de código aberto que é "alpha" e é baseada em uma API interna muito estável e muito usada .)


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

É mais curto que

new List<string> { "item" };

e você não precisa especificar o tipo.


7

Use um método de extensão com encadeamento de métodos.

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

Isso permitiria que você faça isso:

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

ou

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

Atualizar

Agora você pode usar inicializadores de lista:

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

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


Talvez isso se deva às versões mais recentes do C # desde 2009, mas acho new List<string> {"Yes"}que é melhor ...?
ErikE

@ErikE De acordo com a documentação da Microsoft ( msdn.microsoft.com/en-us/library/bb384062(v=vs.90).aspx ), isso era suportado no Visual Studio 2008. Não me lembro disso há muito tempo para dizer definitivamente se Eu complicava demais isso na época. Atualizando.
Michael Meadows

7

Mais uma maneira, encontrada em "C # /. Net Little wonders" (infelizmente, o site não existe mais):

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

Confuso, mas inteligente.
PRMan 26/09

4

Para um único item enumerável em java, seria Collections.singleton ("string");

No c #, isso será mais eficiente do que uma nova 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;
    }
}

mas existe uma maneira mais simples de usar a estrutura?


Essa é realmente a melhor resposta na minha opinião. É um padrão muito comum ter uma única lista de itens, para reduzir o tamanho da alocação. Se você já está procurando um atalho, pode combinar o conveniente com o bom.
Alex


2

Eu tenho essa pequena função:

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

Como ele não prescreve um tipo de retorno concreto, é tão genérico que eu o uso em todo o lugar. Seu código seria semelhante

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

Mas é claro que também permite

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

Costumo usá-lo quando tenho que acrescentar / acrescentar um item à saída de uma instrução LINQ. Por exemplo, para adicionar um item em branco a uma lista de seleção:

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

Salva alguns ToList()e Adddeclarações.

(Resposta tardia, mas me deparei com essa velhinha e achei que isso poderia ser útil)



2

Inspirado nas outras respostas (e assim eu posso buscá-lo sempre que preciso!), Mas com o nome / estilo alinhado com o F # (que possui uma singletonfunção padrão por estrutura de dados *):

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

* exceto por ResizeArraysi mesmo, é claro, daí esta questão :)


Na prática, na verdade, nomeia-o Createpara alinhar com outros ajudantes que definem tais 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);
    }
}

Obrigado! Minha solução também. Algumas coisas: (1) a implementação da sua lista não é pública, portanto não pode ser usada fora do assembly declarante e (2) qual é o objetivo de colocá-las no namespace System?
código é o seguinte

A razão de @StephenRobinson para colocar a Lazyextensão Systemé que Lazyela mesma está dentro System[e, portanto Create, apareceria nas listas de complementos sem a using]. Não há nada a ganhar ao forçar as pessoas a openum espaço de nome diferente? Tornar a outra coisa privada não era intencional; resolvido #
Ruben Bartelink 06/04

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.