Como inicializar facilmente uma lista de tuplas?

Eu amo tuplas . Eles permitem que você agrupe rapidamente informações relevantes sem ter que escrever uma estrutura ou class para isso. Isso é muito útil ao refatorar o código muito localizado.

Inicializando uma lista deles, no entanto, parece um pouco redundante.

var tupleList = new List<Tuple> { Tuple.Create( 1, "cow" ), Tuple.Create( 5, "chickens" ), Tuple.Create( 1, "airplane" ) }; 

Não há um caminho melhor? Eu adoraria uma solução ao longo das linhas do inicializador Dicionário .

 Dictionary students = new Dictionary() { { 111, "bleh" }, { 112, "bloeh" }, { 113, "blah" } }; 

Não podemos usar uma syntax semelhante?

c # 7.0 permite fazer isso:

  var tupleList = new List<(int, string)> { (1, "cow"), (5, "chickens"), (1, "airplane") }; 

Se você não precisa de uma List , mas apenas de uma matriz, você pode fazer:

  var tupleList = new(int, string)[] { (1, "cow"), (5, "chickens"), (1, "airplane") }; 

E se você não gosta de “Item1” e “Item2”, você pode fazer:

  var tupleList = new List<(int Index, string Name)> { (1, "cow"), (5, "chickens"), (1, "airplane") }; 

ou

  var tupleList = new (int Index, string Name)[] { (1, "cow"), (5, "chickens"), (1, "airplane") }; 

que permite fazer: tupleList[0].Index e tupleList[0].Name

Framework 4.6.2 e abaixo

Você deve instalar o System.ValueTuple no Nuget Package Manager.

Framework 4.7 e acima

Ele é construído no framework. Não instale System.ValueTuple . Na verdade, remova-o e exclua-o do diretório bin.

nota: Na vida real, eu não seria capaz de escolher entre vaca, galinhas ou avião. Eu ficaria muito dividido.

Sim! Isso é possível .

A syntax {} do inicializador de coleção funciona em qualquer tipo IEnumerable que tenha um método Add com a quantidade correta de argumentos. Sem se preocupar como isso funciona, isso significa que você pode simplesmente estender de List , adicionar um método Add personalizado para inicializar seu T e pronto!

 public class TupleList : List> { public void Add( T1 item, T2 item2 ) { Add( new Tuple( item, item2 ) ); } } 

Isso permite que você faça o seguinte:

 var groceryList = new TupleList { { 1, "kiwi" }, { 5, "apples" }, { 3, "potatoes" }, { 1, "tomato" } }; 

C # 6 adiciona um novo recurso apenas para isso: extensão Adicionar methods. Isso sempre foi possível para o VB.net, mas agora está disponível em C #.

Agora você não precisa adicionar methods Add() às suas classs diretamente, você pode implementá-los como methods de extensão. Ao estender qualquer tipo enumerável com um método Add() , você poderá usá-lo nas expressões do inicializador de coleção. Então você não precisa mais derivar de listas explicitamente ( como mencionado em outra resposta ), você pode simplesmente estendê-lo.

 public static class TupleListExtensions { public static void Add(this IList> list, T1 item1, T2 item2) { list.Add(Tuple.Create(item1, item2)); } public static void Add(this IList> list, T1 item1, T2 item2, T3 item3) { list.Add(Tuple.Create(item1, item2, item3)); } // and so on... } 

Isso permitirá que você faça isso em qualquer class que implemente o IList<> :

 var numbers = new List> { { 1, "one" }, { 2, "two" }, { 3, "three" }, { 4, "four" }, { 5, "five" }, }; var points = new ObservableCollection> { { 0, 0, 0 }, { 1, 2, 3 }, { -4, -2, 42 }, }; 

É claro que você não está restrito a estender collections de tuplas, pode ser para collections de qualquer tipo específico para o qual você deseja a syntax especial.

 public static class BigIntegerListExtensions { public static void Add(this IList list, params byte[] value) { list.Add(new BigInteger(value)); } public static void Add(this IList list, string value) { list.Add(BigInteger.Parse(value)); } } var bigNumbers = new List { new BigInteger(1), // constructor BigInteger(int) 2222222222L, // implicit operator BigInteger(long) 3333333333UL, // implicit operator BigInteger(ulong) { 4, 4, 4, 4, 4, 4, 4, 4 }, // extension Add(byte[]) "55555555555555555555555555555555555555", // extension Add(string) }; 

C # 7 estará adicionando suporte para tuplas embutidas no idioma, embora elas sejam de um tipo diferente ( System.ValueTuple ). Então, seria bom adicionar sobrecargas para as tuplas de valor, para que você tenha a opção de usá-las também. Infelizmente, não há conversões implícitas definidas entre os dois.

 public static class ValueTupleListExtensions { public static void Add(this IList> list, ValueTuple item) => list.Add(item.ToTuple()); } 

Desta forma, a boot da lista ficará ainda melhor.

 var points = new List> { (0, 0, 0), (1, 2, 3), (-1, 12, -73), }; 

Mas, em vez de passar por todo esse problema, talvez seja melhor mudar para o uso exclusivo do ValueTuple .

 var points = new List<(int, int, int)> { (0, 0, 0), (1, 2, 3), (-1, 12, -73), }; 

Você pode fazer isso chamando o construtor cada vez com um pouco melhor

 var tupleList = new List> { new Tuple(1, "cow" ), new Tuple( 5, "chickens" ), new Tuple( 1, "airplane" ) }; 

Pergunta antiga, mas isso é o que eu geralmente faço para tornar as coisas um pouco mais legíveis:

 Func> tc = Tuple.Create; var tupleList = new List> { tc( 1, "cow" ), tc( 5, "chickens" ), tc( 1, "airplane" ) }; 

Por que você gosta de tuplas? É como tipos anônimos: sem nomes. Não é possível entender a estrutura de dados.

Eu gosto de aulas clássicas

 class FoodItem { public int Position { get; set; } public string Name { get; set; } } List list = new List { new FoodItem { Position = 1, Name = "apple" }, new FoodItem { Position = 2, Name = "kiwi" } }; 

Uma técnica que acho um pouco mais fácil e que não foi mencionada antes aqui:

 var asdf = new [] { (Age: 1, Name: "cow"), (Age: 2, Name: "bird") }.ToList(); 

Eu acho que é um pouco mais limpo que:

 var asdf = new List> { (Age: 1, Name: "cow"), (Age: 2, Name: "bird") }; 
  var colors = new[] { new { value = Color.White, name = "White" }, new { value = Color.Silver, name = "Silver" }, new { value = Color.Gray, name = "Gray" }, new { value = Color.Black, name = "Black" }, new { value = Color.Red, name = "Red" }, new { value = Color.Maroon, name = "Maroon" }, new { value = Color.Yellow, name = "Yellow" }, new { value = Color.Olive, name = "Olive" }, new { value = Color.Lime, name = "Lime" }, new { value = Color.Green, name = "Green" }, new { value = Color.Aqua, name = "Aqua" }, new { value = Color.Teal, name = "Teal" }, new { value = Color.Blue, name = "Blue" }, new { value = Color.Navy, name = "Navy" }, new { value = Color.Pink, name = "Pink" }, new { value = Color.Fuchsia, name = "Fuchsia" }, new { value = Color.Purple, name = "Purple" } }; foreach (var color in colors) { stackLayout.Children.Add( new Label { Text = color.name, TextColor = color.value, }); FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)) } this is a Tuple