views:

2149

answers:

17

That is, I'd like to have a tuple of values.

The use case on my mind:

Dictionary<Pair<string, int>, object>

or

Dictionary<Triple<string, int, int>, object>

Are there built-in types like Pair or Triple? Or what's the best way of implementing it?

Update There are some general-purpose tuples implementations described in the answers, but for tuples used as keys in dictionaries you should additionaly verify correct calculation of the hash code. Some more info on that in another question.

Update 2 I guess it is also worth reminding, that when you use some value as a key in dictionary, it should be immutable.

+3  A: 

I usually just create my own struct, containing the values. It's often a bit more readable ;)

Grad van Horck
A: 

There aren't built ins, but a Pair<T,R> class is trivial to create.

Will
+8  A: 

Pair and Triplet are existing classes in .net see msdn:

Triplet

Pair

I recently came across them, while playing around with viewstate decoding

snomag
1. They are in Web.UI :-)2. They aren't generic3. What about GetHashCode?
Yacoder
I am a big fan of the Triplet when adding controls dynamically to a web page.
David Basarab
1, Yes they are, as I said I saw it being used in an asp.net site, so I thought I would mention it.2, That's true again, if you need something generic, I'd go with yshuditelu's solution3, What about it?
snomag
3. If they don't override GetHashCode() and Equals() you can't use it for keys in collections. See link in the question.
Yacoder
+10  A: 
public struct Pair<T1, T2>
{
    public T1 First;
    public T2 Second;
}

public struct Triple<T1, T2, T3>
{
    public T1 First;
    public T2 Second;
    public T3 Third;
}
Timothy Carter
A: 

Aye, there's System.Web.UI.Pair and System.Web.UI.Triplet (which has an overloaded creator for Pair-type behaviour!)

ballpointpeon
A: 

For the first case, I usually use

Dictionary<KeyValuePair<string, int>, object>
Jonas Lincoln
A: 

There are not built-in classes for that. You can use KeyValuePair or roll out your own implementation.

aku
A: 

You could use System.Collections.Generic.KeyValuePair as your Pair implementation.

Or you could just implement your own, they aren't hard:

public class Triple<T, U, V>
{
  public T First {get;set;}
  public U Second {get;set;}
  public V Third {get;set;}
}

Of course, you may someday run into a problem that Triple(string, int, int) is not compatible with Triple(int, int, string). Maybe go with System.Xml.Linq.XElement instead.

David B
This implementation is wrong. See link in the question. If you use class for the tuple, you can't use it as a key in dictionary because unless you override the GetHashCode()
Yacoder
+3  A: 

I have implemented a tuple library in C#. Visit http://www.adventuresinsoftware.com/generics/ and click on the "tuples" link.

Michael L Perry
Yeah, this seems to be quite a good implementation. Would you mind maybe posting your code for the Tuple class here?It also seems to me that there is an overflow possibility in your GetHashCode() function, isn't there?
Yacoder
And I like the "Sextuple" class ;-)
Yacoder
Sorry, I don't have enough characters to post the code here.I should put "unchecked" on the GetHashCode method. Good catch.
Michael L Perry
Well, maybe a somewhat shortened version to give a quick example?.. Er, without the ToString()... As for the GetHashCode() my intention would be to use modulus calc (%), but then your idea seems to be better: we just need "some" int as fast as possible.
Yacoder
A: 

The System.Collections.Generics namespace does have a generic structure called KeyValuePair. This is the type used by the generic dictionary - I expect you could setup something like:

Dictionary<KeyValuePair<string, int>, object>

as your pair. For your Triple, I believe the best approach to take may be to setup your own generic struct to use.

Remi Despres-Smyth
Be careful with this, KeyValuePair comparisons are relatively slow.
Keith
A: 

There are also the Tuple<> types in F#; you just need to reference FSharp.Core.dll.

TraumaPony
+2  A: 

KeyValuePair is the best class to extend if you don't want to create your own classes.

int id = 33;
string description = "This is a custom solution";
DateTime created = DateTime.Now;

KeyValuePair<int, KeyValuePair<string, DateTime>> triple =
   new KeyValuePair<int, KeyValuePair<string, DateTime>>();
triple.Key = id;
triple.Value.Key = description;
triple.Value.Value = created;

You can extend it to as many levels as you want.

KeyValuePair<KeyValuePair<KeyValuePair<string, string>, string, string> quadruple =
   new KeyValuePair<KeyValuePair<KeyValuePair<string, string>, string, string>();

Note: The classes Triplet and Pair exists inside the System.Web-dll, so it's not very suitable for other solutions than ASP.NET.

Seb Nilsson
+13  A: 

Builtin Classes

In certain specific cases, the .net framework already provides tuple-like classes that you may be able to leverage.

Pairs and Triples

The generic System.Collections.Generic.KeyValuePair class could be used as an adhoc pair implementation. This is the class that the generic Dictionary uses internally.

Alternatively, you may be able to make do with the System.Collections.DictionaryEntry structure that acts as a rudimentary pair and has the advantage of being available in mscorlib. On the down side, however, is that this structure is not strongly typed.

Pairs and Triples are also available in the form of the System.Web.UI.Pair and System.Web.UI.Triplet classes. Even though theses classes live in the the System.Web assembly they might be perfectly suitable for winforms development. However, these classes are not strongly typed either and might not be suitable in some scenarios, such as a general purposed framework or library.

Higher order tuples

For higher order tuples, short of rolling your own class, there may not be a simple solution.

If you have installed the F# language, you could reference the FSharp.Core.dll that contains a set of generic immutable Microsoft.Fsharp.Core.Tuple classes up to generic sextuples. However, even though an unmodified FSharp.Code.dll can be redistributed, F# is a research language and a work in progress so this solution is likely to be of interest only in academic circles.

If you do not want to create your own class and are uncomfortable referencing the F# library, one nifty trick could consist in extending the generic KeyValuePair class so that the Value member is itself a nested KeyValuePair.

For instance, the following code illustrates how you could leverage the KeyValuePair in order to create a Triples:

int id = 33;
string description = "This is a custom solution";
DateTime created = DateTime.Now;

KeyValuePair<int, KeyValuePair<string, DateTime>> triple =
   new KeyValuePair<int, KeyValuePair<string, DateTime>>();
triple.Key = id;
triple.Value.Key = description;
triple.Value.Value = created;

This allows to extend the class to any arbitrary level as is required.

KeyValuePair<KeyValuePair<KeyValuePair<string, string>, string>, string> quadruple =
    new KeyValuePair<KeyValuePair<KeyValuePair<string, string>, string>, string>();
KeyValuePair<KeyValuePair<KeyValuePair<KeyValuePair<string, string>, string>, string>, string> quintuple =
    new KeyValuePair<KeyValuePair<KeyValuePair<KeyValuePair<string, string>, string>, string>, string>();

Roll Your Own

In other cases, you might need to resort to rolling your own tuple class, and this is not hard.

You can create simple structures like so:

struct Pair<T, R>
{
    private T first_;
    private R second_;

    public T First
    {
        get { return first_; }
        set { first_ = value; }
    }

    public R Second
    {
        get { return second_; }
        set { second_ = value; }
    }
}

Frameworks and Libraries

This problem has been tackled before and general purpose frameworks do exist. Below is a link to one such framework:

Maxime Labelle
Excellent summary of all the available methods.
Ron Warholic
The .NET 4.0 library that's currently in beta also includes tuples.
Ian G
+2  A: 

You can relatively easily create your own tuple classes, the only thing that potentially gets messy is your equality and hashcode overrides (essential if you're going to use them in dictionaries).

It should be noted that .Net's own KeyValuePair<TKey,TValue> struct has relatively slow equality and hashcode methods.

Assuming that isn't a concern for you there is still the problem that the code ends up being hard to figure out:

public Tuple<int, string, int> GetSomething() 
{
    //do stuff to get your multi-value return
}

//then call it:
var retVal = GetSomething();

//problem is what does this mean?
retVal.Item1 / retVal.Item3; 
//what are item 1 and 3?

In most of these cases I find it easier to create a specific record class (at least until C#4 makes this compiler-magic)

class CustomRetVal {
    int CurrentIndex { get; set; }
    string Message { get; set; }
    int CurrentTotal { get; set; }
}

var retVal = GetSomething();

//get % progress
retVal.CurrentIndex / retVal.CurrentTotal;
Keith
+1  A: 

NGenerics - the popular .Net algorithms and data structures library, has recently introduced immutable data structures to the set.

The first immutable ones to implement were pair and tuple classes. The code is well covered with tests and is quite elegant. You can check it here. They are working on the other immutable alternatives at the moment and they should be ready shortly.

husayt
A: 

One simple solution has no been mentioned yet. You can also just use a List<T>. It's built in, efficient and easy to use. Granted, it looks a bit weird at first, but it does its job perfectly, especially for a larger count of elements.

mafutrct
+1  A: 

Fast-forward to 2010, .NET 4.0 now supports n-tuples of arbitrary n. These tuples implement structural equality and comparison as expected.

Mauricio Scheffer