1

I'm having some problem decide on the data container:

I need to hold an array of key, value, so I can access the data by index.

I started with a:

static Tuple<string, string>[] kv = {
    Tuple.Create("K1", "V1"),
    Tuple.Create("K2", "V2"),
    Tuple.Create("K3", "V3"),
};

var index = 1;
Console.WriteLine(kv[index].Item1);
Console.WriteLine(kv[index].Item2);

On the other hand I can simply use a struct or a class:

public struct KV
{            
    public string K;
    public string V;
}

static KV[] kv =
{
    new KV { K = "K1", V = "V1"  },
    // etc...
};


Console.WriteLine(kv[index].K);
Console.WriteLine(kv[index].V); 

Is there any advantage to using the Tuple over the struct/class approach? or is there any other better container than the above to hold such data?

johnny 5
  • 19,893
  • 50
  • 121
  • 195
zig
  • 4,524
  • 1
  • 24
  • 68
  • 1
    Assuming the keys are unique, a [`Dictionary`](https://msdn.microsoft.com/en-us/library/xfhwa508(v=vs.110).aspx) is usually used here. – Rufus L May 10 '18 at 18:12
  • 1
    I may be missing something, but is there a reason you're not using a `Dictionary`? https://msdn.microsoft.com/en-us/library/xfhwa508(v=vs.110).aspx – Arash Motamedi May 10 '18 at 18:13
  • The advantage of a struct over a tuple is that it gives you named fields. As the complexity of your program grows, it might not be clear what the original intention of the values were if they are in tuple. A tuple may have a smaller memory foot print than a struct, but it is probably negligible if you are programming in a higher level language. – MCH May 10 '18 at 18:13
  • 1
    @Rufus L, I need to access the data by index, which AFAIK you cant for a Dictionary – zig May 10 '18 at 18:17
  • FYI with C# 7 you can use the new value tuples and have names `(string Key, string Value)[]` thought I only prefer that if the array has a limited scope. – juharr May 10 '18 at 18:17
  • Oh, i see. If you need to rely on the order of items (i.e. reference by index), then you might want a `List` (a [`KeyValuePair`](https://msdn.microsoft.com/en-us/library/5tbh8a42(v=vs.110).aspx) is a struct similar to the one you created above) – Rufus L May 10 '18 at 18:22
  • Another option if the keys are unique and you need to guarantee an order is to have a `Dictionary` and a `List` to index the keys. – juharr May 10 '18 at 18:22
  • Dictionary, SortedDictionary, and Dictionary all allow you to lookup values by a key. Read the answer in this link for the differences. https://stackoverflow.com/questions/1427147/sortedlist-sorteddictionary-and-dictionary – Jim Berg May 10 '18 at 18:23
  • _I need to access the data by index_ You can have a key as index – JohnyL May 10 '18 at 18:44
  • It's not really clear as to what you're after. When you say index, I'm thinking that you want to be able to lookup values as though they are indexed in a database; A quick way to find a particular value. If you mean that you want to use an indexer like an array, why not use an array? If it must allow for dynamic sizing, use a List. If you do want to access objects like they're indexed, use a Dictionary. If you need the Keys to be sorted when you enumerate through them, use a SortedDictionary. If you need to lookup based on a value or an indexer, use a SortedList. – Jim Berg May 10 '18 at 18:48

2 Answers2

1

Is there any advantage to using the Tuple

its built in, you don't need to manually create another struct/class. Other than that they are pretty much the same.

Or you can use a KeyValuePair which does exactly the same thing.

Steve
  • 11,696
  • 7
  • 43
  • 81
1

The usual way to create a custom data type (similar to what you are asking) in C# is to use class or struct.

class Foo { int test; string name; }
struct Foo { int test; string name; }

var foo = new Foo() {test = 10, name = "some_name"};

As you will notice, this works great when we need a lot of customization in the class - attributes, methods, properties, etc. But numerous times, we just don't need all that bells and frills. We just need to pass multiple variables of different types

With the release of LINQ in .NET Framework 2.0, came anonymous type classes which provide named but read-only properties with a concise syntax, but these types were limited to being used within a method, and cannot be passed between methods.

var foo = new {test = 10, name = "some_name" }

In .NET Framework 4.0, they came up with the Tuple struct. There is no magic here, it is just a predefined generic struct. There are variants of this struct with up-to 8 members of different types.

var foo = new Tuple<int, string>(10, "some_name");

var foo = Tuple.Create(10, "some_name");

The obvious limitation to this approach was that the members had generic names like Item1, Item2, etc - making it unsuitable to pass data over "long distance". And the benefit was that it was very concise without unwanted overhead.

With the newest version of C# 7, they are working towards combining the benefits of anonymous types and Tuple, to anonymous tuple types (called ValueTuple ) which can be passed between functions. In fact they can be created implicitly with concise syntax.

(test, name) Foo() {
    return Bar()
}
(test, name) Bar() {
    return (1, "new_name");
}

var allItems = new List<(int test, string name)>() {
    (1, "some_name"),
    (2, "new_name"),
}

With all this background, I would highly recommend using the ValueTuple for data structures which serve as containers to pass data, and to write an explicit class or struct when you need more expressive power (attributes, properties, methods, etc)

Typically speaking, when you have very few members (say less than 5), ideally of ValueType, you will get performance benefits on using ValueTuple which are struct. I would not recommend to focus on this aspect though, unless it is very performance centric application.

Update:
To make sure you can use the ValueTuple, you might have to check and confirm a few things.

  1. Make sure you are using C# 7 or higher (Project Properties -> Build -> Advanced -> Language Version)?
  2. Make sure you are using .NET framework 4.7 or higher (Project Properties -> Application -> Target Framework)?
  3. If your .NET Framework version is lower than 4.7, then you can either install the .NET framework version 4.7 (or higher) or install the System.ValueTuple nuget package. There is no using clause to refer to it.
Vikhram
  • 4,294
  • 1
  • 20
  • 32
  • I'm on VS 2017, the `var allItems = new List<(int test, string name)>()...` wont compile. what to do to make it work or what reference should I add? – zig May 11 '18 at 16:21