How to easily initialize a list of Tuples?
Solution 1
c# 7.0 lets you do this:
var tupleList = new List<(int, string)>
{
(1, "cow"),
(5, "chickens"),
(1, "airplane")
};
If you don't need a List
, but just an array, you can do:
var tupleList = new(int, string)[]
{
(1, "cow"),
(5, "chickens"),
(1, "airplane")
};
And if you don't like "Item1" and "Item2", you can do:
var tupleList = new List<(int Index, string Name)>
{
(1, "cow"),
(5, "chickens"),
(1, "airplane")
};
or for an array:
var tupleList = new (int Index, string Name)[]
{
(1, "cow"),
(5, "chickens"),
(1, "airplane")
};
which lets you do: tupleList[0].Index
and tupleList[0].Name
Framework 4.6.2 and below
You must install System.ValueTuple
from the Nuget Package Manager.
Framework 4.7 and above
It is built into the framework. Do not install System.ValueTuple
. In fact, remove it and delete it from the bin directory.
note: In real life, I wouldn't be able to choose between cow, chickens or airplane. I would be really torn.
Solution 2
Yes! This is possible.
The { } syntax of the collection initializer works on any IEnumerable type which has an Add method with the correct amount of arguments. Without bothering how that works under the covers, that means you can simply extend from List<T>, add a custom Add method to initialize your T, and you are done!
public class TupleList<T1, T2> : List<Tuple<T1, T2>>
{
public void Add( T1 item, T2 item2 )
{
Add( new Tuple<T1, T2>( item, item2 ) );
}
}
This allows you to do the following:
var groceryList = new TupleList<int, string>
{
{ 1, "kiwi" },
{ 5, "apples" },
{ 3, "potatoes" },
{ 1, "tomato" }
};
Solution 3
C# 6 adds a new feature just for this: extension Add methods. This has always been possible for VB.net but is now available in C#.
Now you don't have to add Add()
methods to your classes directly, you can implement them as extension methods. When extending any enumerable type with an Add()
method, you'll be able to use it in collection initializer expressions. So you don't have to derive from lists explicitly anymore (as mentioned in another answer), you can 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...
}
This will allow you to do this on any class that implements IList<>
:
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 restricted to extending collections of tuples, it can be for collections of any specific type you want the special syntax for.
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 be adding in support for tuples built into the language, though they will be of a different type (System.ValueTuple
instead). So to it would be good to add overloads for value tuples so you have the option to use them as well. Unfortunately, there are no implicit conversions defined between the two.
public static class ValueTupleListExtensions
{
public static void Add<T1, T2>(this IList<Tuple<T1, T2>> list,
ValueTuple<T1, T2> item) => list.Add(item.ToTuple());
}
This way the list initialization will look even nicer.
var points = new List<Tuple<int, int, int>>
{
(0, 0, 0),
(1, 2, 3),
(-1, 12, -73),
};
But instead of going through all this trouble, it might just be better to switch to using ValueTuple
exclusively.
var points = new List<(int, int, int)>
{
(0, 0, 0),
(1, 2, 3),
(-1, 12, -73),
};
Solution 4
You can do this by calling the constructor each time with is slightly better
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" )
};
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" )
};
Steven Jeuris
I have a PhD in Human-Computer Interaction and am currently working both as a software engineer at iMotions and as a postdoc at the Technical University of Denmark (DTU). This blend of research and development is the type of work which motivates and excites me the most. Currently, I am working on a distributed platform which enables researchers to conduct biometric research 'in the wild' (outside of the lab environment). As part of my previous research, I developed a fully functional system (called Laevo), exploring an alternative to the prevalent, antiquated, desktop computing paradigm. This work (and related publications) contributes to a line of research called 'activity-centric computing'. I have almost 10 years of professional software development experience. Prior to academia, I worked for several years as a professional full-stack software developer at a game development company in Belgium: AIM Productions. I immediately started working here after a successful internship concluding my bachelor degree (obtained in 2007). My job entailed working on interactive hometrainer software and other multimedia applications. This spiked my interest in user interface development. I liked the work and colleagues at the company too much to give up entirely for further studies, so I decided to combine the two. In 2009 I started studying for my master in Game and Media Technology at the University of Utrecht in the Netherlands, from which I graduated in 2012.
Updated on February 11, 2021Comments
-
Steven Jeuris over 3 years
I love tuples. They allow you to quickly group relevant information together without having to write a struct or class for it. This is very useful while refactoring very localized code.
Initializing a list of them however seems a bit redundant.
var tupleList = new List<Tuple<int, string>> { Tuple.Create( 1, "cow" ), Tuple.Create( 5, "chickens" ), Tuple.Create( 1, "airplane" ) };
Isn't there a better way? I would love a solution along the lines of the Dictionary initializer.
Dictionary<int, string> students = new Dictionary<int, string>() { { 111, "bleh" }, { 112, "bloeh" }, { 113, "blah" } };
Can't we use a similar syntax?
-
goodeye over 11 yearsA downside is having to write the class. Like you, I love tuples because I don't have to write a class or struct.
-
onedaywhen over 11 yearsI couldn't get the original code to work, so I've amended it to what I think it should be... which may reverse your opinion on whether the syntax "is slightly better" after all :)
-
Steven Jeuris almost 9 years@BillW Not too certain this is the exact post, ... but I know Jon Skeet has written about it before.
-
Andreas Reiff over 8 yearsHow do you get the value/name syntax with a Tuple?
-
cthepenier over 8 yearsCompiler tells that anonymous type are not implicitly convertible to Tuple
-
Dave Cousineau about 8 yearsat least use
Tuple.Create
instead and you can infer the type arguments -
Byyo about 8 yearsdoes this work
groceryList[0] == groceryList[1]
or does a comparison have to be implemented? -
Steven Jeuris over 7 yearsI finally took a decent look at this while updating my library to C# 6.0. Although it looks good at a glance, I prefer my previously posted solution over this because I find
TupleList<int, string>.
to be more readable thanList<Tuple<int, string>>
. -
Jeff Mercado over 7 yearsThat's something that a type alias can fix. Granted the alias itself cannot be generic which may be preferable.
using TupleList = System.Collections.Generic.List<System.Tuple<int, string>>;
-
Suraj over 7 yearsI created a Nuget Package with Add methods on ICollection to save others the time of having to maintain this code. See here for package: nuget.org/packages/Naos.Recipes.TupleInitializers See here for code: github.com/NaosProject/Naos.Recipes/blob/master/… This will include a cs file in your solution under a ".Naos.Recipes" folder, so you don't have to drag-around an assembly dependency
-
Suraj over 7 yearsI created a Nuget Package with Add methods on ICollection to save others the time of having to maintain this code. See here for package: nuget.org/packages/Naos.Recipes.TupleInitializers See here for code: github.com/NaosProject/Naos.Recipes/blob/master/… This will include a cs file in your solution under a ".Naos.Recipes" folder, so you don't have to drag-around an assembly dependency
-
Steven Jeuris over 6 yearsThat comes more down to taste whether you prefer to mention types explicitly or not, in the same vain as to use
var
or not. I personally prefer explicit typing (when it is not duplicated in e.g. the constructor). -
Алекса Јевтић about 6 yearsCan this be used on a .net core 2.0 ?
-
toddmo about 6 years@АлексаЈевтић,
System.ValueTuple
supports core 2.0. But, try it without the Nuget first, as unnecessary packages can cause problems. So one way or another, yes. Use c# v7 or greater if possible. -
Ed Bayiates almost 6 yearsWorks on old versions of .NET, too!
-
Steven Jeuris over 5 yearsYou make me feel old. :) I might be missing something here, but initializing 'holds' is not concise at all. This was the exact point of the question.
-
djangojazz over 5 years@Steven Jeuris No, you were right I copied and pasted the wrong bit of code for Point 1. Need to go a little slower before I hit 'submit'.
-
Vitox over 4 yearsAbsolutely perfect answer! Thanks!
-
pmcnamee almost 3 yearsHere's a relevant microsoft link about the collection initializers mentioned in this answer.
-
Rod Talingting over 2 yearsThis is what I was looking for. Thanks @onedaywhen