Problem
Tuples are one of my favorite things. They enable you to rapidly group relevant data without having to create a struct or class for it. This comes in handy when refactoring highly localized code.
However, it appears that creating a list of them is redundant.
var tupleList = new List<Tuple<int, string>>
{
Tuple.Create( 1, "cow" ),
Tuple.Create( 5, "chickens" ),
Tuple.Create( 1, "airplane" )
};
Isn’t there a more efficient way? I’d like to see something similar to the Dictionary initializer.
Dictionary<int, string> students = new Dictionary<int, string>()
{
{ 111, "bleh" },
{ 112, "bloeh" },
{ 113, "blah" }
};
Isn’t it possible to utilize a similar syntax?
Asked by Steven Jeuris
Solution #1
This is possible with c# 7.0:
var tupleList = new List<(int, string)>
{
(1, "cow"),
(5, "chickens"),
(1, "airplane")
};
If you only require an array and don’t need a List, you can do:
var tupleList = new(int, string)[]
{
(1, "cow"),
(5, "chickens"),
(1, "airplane")
};
If you don’t like “Item1” and “Item2,” you can perform the following:
var tupleList = new List<(int Index, string Name)>
{
(1, "cow"),
(5, "chickens"),
(1, "airplane")
};
Alternatively, in the case of an array:
var tupleList = new (int Index, string Name)[]
{
(1, "cow"),
(5, "chickens"),
(1, "airplane")
};
This allows you to perform the following: tupleList[0]. tupleList[0] and index Name
Frameworks older than 4.6.2
System must be installed. The Nuget Package Manager’s ValueTuple.
Framework version 4.7 and above
It’s part of the framework. System should not be installed. ValueTuple. In fact, remove it from the bin directory and destroy it.
I wouldn’t be able to select between a cow, chickens, or an airplane in real life. I’d be torn between the two options.
Answered by toddmo
Solution #2
Yes! This is a viable option.
public class TupleList<T1, T2> : List<Tuple<T1, T2>>
{
public void Add( T1 item, T2 item2 )
{
Add( new Tuple<T1, T2>( item, item2 ) );
}
}
This enables you to carry out the following tasks:
var groceryList = new TupleList<int, string>
{
{ 1, "kiwi" },
{ 5, "apples" },
{ 3, "potatoes" },
{ 1, "tomato" }
};
Answered by Steven Jeuris
Solution #3
Extension Add methods are a new feature in C# 6 that was created specifically for this purpose. This has always been feasible with VB.net, but it is now doable with C# as well.
You can now implement Add() methods as extension methods rather than adding them to your classes directly. When you add an Add() function to any enumerable type, you can use it in collection initializer expressions. So, instead of explicitly deriving from lists (as suggested in another answer), you may simply extend it.
public static class TupleListExtensions
{
public static void Add<T1, T2>(this IList<Tuple<T1, T2>> list,
T1 item1, T2 item2)
{
list.Add(Tuple.Create(item1, item2));
}
public static void Add<T1, T2, T3>(this IList<Tuple<T1, T2, T3>> list,
T1 item1, T2 item2, T3 item3)
{
list.Add(Tuple.Create(item1, item2, item3));
}
// and so on...
}
You can accomplish this on any class that implements IList> with this code:
var numbers = new List<Tuple<int, string>>
{
{ 1, "one" },
{ 2, "two" },
{ 3, "three" },
{ 4, "four" },
{ 5, "five" },
};
var points = new ObservableCollection<Tuple<double, double, double>>
{
{ 0, 0, 0 },
{ 1, 2, 3 },
{ -4, -2, 42 },
};
Of course, you’re not limited to expanding tuple collections; you may use the special syntax for any form of collection you want.
public static class BigIntegerListExtensions
{
public static void Add(this IList<BigInteger> list,
params byte[] value)
{
list.Add(new BigInteger(value));
}
public static void Add(this IList<BigInteger> list,
string value)
{
list.Add(BigInteger.Parse(value));
}
}
var bigNumbers = new List<BigInteger>
{
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 will provide built-in support for tuples, however they will be of a different type (System.ValueTuple instead). As a result, it would be beneficial to include overloads for value tuples so that you can utilize them as well. Unfortunately, no implicit conversions between the two are defined.
public static class ValueTupleListExtensions
{
public static void Add<T1, T2>(this IList<Tuple<T1, T2>> list,
ValueTuple<T1, T2> item) => list.Add(item.ToTuple());
}
The list initialization will appear considerably prettier this way.
var points = new List<Tuple<int, int, int>>
{
(0, 0, 0),
(1, 2, 3),
(-1, 12, -73),
};
However, rather to going through all of this difficulty, it may be preferable to simply use ValueTuple entirely.
var points = new List<(int, int, int)>
{
(0, 0, 0),
(1, 2, 3),
(-1, 12, -73),
};
Answered by Jeff Mercado
Solution #4
This can be accomplished by repeatedly invoking the constructor, which is slightly more efficient.
var tupleList = new List<Tuple<int, string>>
{
new Tuple<int, string>(1, "cow" ),
new Tuple<int, string>( 5, "chickens" ),
new Tuple<int, string>( 1, "airplane" )
};
Answered by Kevin Holditch
Solution #5
Old question, but this is what I typically do to make things a bit more readable:
Func<int, string, Tuple<int, string>> tc = Tuple.Create;
var tupleList = new List<Tuple<int, string>>
{
tc( 1, "cow" ),
tc( 5, "chickens" ),
tc( 1, "airplane" )
};
Answered by Asad Saeeduddin
Post is based on https://stackoverflow.com/questions/8002455/how-to-easily-initialize-a-list-of-tuples