Создание общей функции для преобразования массива в словарь в C #

Jamie Corkhill спросил: 13 июня 2018 в 03:32 в: c#

У меня есть структура, которая содержит две общедоступные переменные. Я создал массив этой структуры и хочу преобразовать ее в словарь.

Вот один из таких способов:

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;
    }
}

Теперь, это работает для моей конкретной настройки, но я хочу попробовать преобразовать функцию KeyValuePairsToDictionary() в Generic, чтобы она работала во всех типах.

Тогда моя первая мысль заключалась в том, чтобы сделайте что-то вроде этого:

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;
}

Как вы, вероятно, можете сказать, я не могу получить доступ к общедоступным полям любого массива struct, который я пытаюсь преобразовать в пары ключ-значение.

С этим, как бы вы предложили мне пойти на выполнение общего преобразования?

Обратите внимание, что для моей конкретной установки требуется, чтобы я преобразовал структуру в словарь, поскольку я использую Unity Game Двигатель.

Спасибо.


2 ответа

Olivier Jacot-Descombes ответил: 14 июня 2018 в 01:41

Общий способ сделать это уже реализован в LINQ.

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

С вашей реализацией

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

и массив

KeyValuePairs[] keyValuePairs = ...;

Вы получаете

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

или, альтернативно

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

Обратите внимание, что первый вариант дает словарь со значениями типа KeyValuePairs, а второй - значения типа float.


Согласно разговору, это кажется, что вас интересует, как вы это реализуете. Вот предложение:

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;
}

Или просто так, если вы хотите сохранить элемент как значение

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;
}
maccettura ответил: 13 июня 2018 в 04:07
Nvm, видимо, селектор значений не нужен ...
Olivier Jacot-Descombes ответил: 13 июня 2018 в 04:12
Если вам нужен Dictionary<string, float>, требуется селектор значений, в противном случае вы получите Dictionary<string, KeyValuePairs>.
Andre.Santarosa ответил: 13 июня 2018 в 04:55

Вы можете использовать Reflection для достижения этого

Прежде всего, добавьте {get;set;} к переменным, чтобы преобразовать их в свойствах

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

Тогда метод

// 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;
}

Я использовал следующий код для тестирования

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);

Дополнительное видео по вопросу: Создание общей функции для преобразования массива в словарь в C #

sizeof что это. sizeof c++ массив. Узнать количество элементов массива. sizeof array. Урок #28.

Модуль 30. Перегрузка операций преобразования типов в языке C#

C++ урок. Перевод из строки в число