1

I have a struct which contains two public variables. I have made an array of that struct, and wish to convert it to a Dictionary.

Here is one such method of accomplishing that:

public class TestClass
{
    public struct KeyValuePairs
    {
        public string variableOne;
        public float variableTwo
    }

    private KeyValuePairs[] keyValuePairs;

    private Dictionary<string, float> KeyValuePairsToDictionary()
    {
        Dictionary<string, float> dictionary = new Dictionary<string, float>();

        for(int i = 0; i < keyValuePairs.Length; i++)
        {
            dictionary.Add(keyValuePairs[i].variableOne, keyValuePairs[i].variableTwo);
        }

        return dictionary;
    }
}

Now, that works for my specific setup, but I wish to try and convert the KeyValuePairsToDictionary() function into a Generic so that it may work across all types.

My first thought, then, was to do something like this:

private Dictionary<T, T> ArrayToDictionary<T>(T[] array)
{
    Dictionary<T, T> keyValuePairs = new Dictionary<T, T>();

    for(int i = 0; i < array.Length; i++)
    {
        keyValuePairs.Add(array[i], array[i]); //The problem is right here.
    }

    return keyValuePairs;
}

As you can probably tell, I can't access the public fields of whatever struct array I am trying to convert into key-value pairs.

With that, how would you suggest I go about performing the generic conversion?

Please note that my specific setup requires that I convert a struct to a dictionary, for I am using the Unity Game Engine.

Thank you.

21
  • 2
    Dictionary<T, T> should be Dictionary<T1, T2> BTW why a generic method and why not an extension method? Commented Jul 7, 2018 at 17:16
  • 1
    I am confused though. Why not use the default KeyValuePair<>? Commented Jul 7, 2018 at 17:20
  • 2
    @JamieCorkhill You could just use Linq's .ToDictionary(). Docs here Commented Jul 7, 2018 at 17:24
  • 2
    @JamieCorkhill no, thats not what I am saying at all. Explain your problem in plain english, do not try to describe the problem with your proposed solution. Tell us what the actual problem you are trying to solve it. Read up on what an XY Problem is Commented Jul 7, 2018 at 17:33
  • 1
    @JamieCorkhill Is there a reason you cannot use ToDictionary()? If you want to see how ToDictionary() works you can just look at the source Commented Jul 7, 2018 at 17:40

2 Answers 2

4

A generic way of doing this is already implemented in LINQ.

var dict = myArray.ToDictionary(a => a.TheKey);

With your implementation

public struct KeyValuePairs
{
    public string variableOne;
    public float variableTwo;
}

and an array

KeyValuePairs[] keyValuePairs = ...;

You get

Dictionary<string, KeyValuePairs> dict = keyValuePairs
    .ToDictionary(a => a.variableOne);

or alternatively

Dictionary<string, float> dict = keyValuePairs
    .ToDictionary(a => a.variableOne, a => a.variableTwo);

Note that the first variant yields a dictionary with values of type KeyValuePairs, while the second one yields values of type float.


According to the conversation, it seems that you are interested on how you would implement this. Here is a suggestion:

public static Dictionary<TKey, TValue> ToDictionary<T, TKey, TValue>(
    this IEnumerable<T> source,
    Func<T, TKey> getKey,
    Func<T, TValue> getValue)
{
    var dict = new Dictionary<TKey, TValue>();
    foreach (T item in source) {
        dict.Add(getKey(item), getValue(item));
    }
    return dict;
}

Or simply like this, if you want to store the item itself as value

public static Dictionary<TKey, T> ToDictionary<T, TKey>(
    this IEnumerable<T> source,
    Func<T, TKey> getKey
{
    var dict = new Dictionary<TKey, T>();
    foreach (T item in source) {
        dict.Add(getKey(item), item);
    }
    return dict;
}
Sign up to request clarification or add additional context in comments.

1 Comment

If you want a Dictionary<string, float> the value selector is required, otherwise you get a Dictionary<string, KeyValuePairs>.
1

You can use Reflection to achieve that

First of all, add a {get;set;} to the variables to transform them in properties

public struct KeyValuePairs
{
    public string variableOne { get; set; }
    public float variableTwo { get; set; }
}

Then the method

// T1 -> Type of variableOne
// T2 -> Type of variableTwo
// T3 -> KeyValuesPair type
public static Dictionary<T1, T2> convert<T1,T2,T3>(T3[] data)
{
    // Instantiate dictionary to return
    Dictionary<T1, T2> dict = new Dictionary<T1, T2>();

    // Run through array
    for (var i = 0;i < data.Length;i++)
    {
        // Get 'key' value via Reflection to variableOne
        var key = data[i].GetType().GetProperty("variableOne").GetValue(data[i], null);
        // Get 'value' value via Reflection to variableTow
        var value = data[i].GetType().GetProperty("variableTwo").GetValue(data[i], null);
        // Add 'key' and 'value' to dictionary casting to properly type
        dict.Add((T1)key, (T2)value);
    }
    //return dictionary
    return dict;
}

I used the following code to test

KeyValuePairs[] val = new KeyValuePairs[5];

val[0] = new KeyValuePairs() { variableOne = "a", variableTwo = 2.4f };
val[1] = new KeyValuePairs() { variableOne = "b", variableTwo = 3.5f };
val[2] = new KeyValuePairs() { variableOne = "c", variableTwo = 4.6f };
val[3] = new KeyValuePairs() { variableOne = "d", variableTwo = 5.7f };
val[4] = new KeyValuePairs() { variableOne = "e", variableTwo = 6.8f };

Dictionary<string, float> dict = convert<string, float,KeyValuePairs>(val);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.