Словарь с двумя значениями, который возвращает любое значение для определенного ключа - PullRequest
2 голосов
/ 26 сентября 2010

Мне нужно создать словарь, который имеет 2 значения на ключ, и он должен вернуть одно из 2 значений с одинаковой вероятностью.

Пример:

myDicry
{
  key = "A", value1=15, value2=56;
}

int firstCall = myDicry["A"];  // = 15
int secondCall = myDicry["A"]; // = 56

Ответы [ 6 ]

9 голосов
/ 26 сентября 2010

Можно было бы написать реализацию IDictionary<TKey, TValue>, которая вела бы себя таким образом, но это не было бы хорошей идеей: большинство людей сочли бы недетерминированный индексатор для класса коллекции очень неинтуитивным.

Вместо этого я предлагаю вам взять на себя ответственность значение за ключ, а не сам словарь.Один из вариантов - написать пользовательский тип, способный выбирать из множества возможностей с равной вероятностью.Например:

public class UnbiasedRandomPicker<T>
{
    private readonly Random _rand = new Random();
    private readonly T[] _possibilities;

    public UnbiasedRandomPicker(params T[] possibilities)
    {
        // argument validation omitted
        _possibilities = possibilities;
    }

    public T GetRandomValue()
    {
        return _possibilities[_rand.Next(_possibilities.Length)];
    }
}

Вы можете использовать словарь так:

var dict = new Dictionary<string, UnbiasedRandomPicker<int>>
{
    {"A", new UnbiasedRandomPicker<int>(15, 56)},
    {"B", new UnbiasedRandomPicker<int>(25, 13)}
};

int randomValueFromA = dict["A"].GetRandomValue();
7 голосов
/ 26 сентября 2010

Нет ничего встроенного в каркас, чтобы сделать это, но вы, вероятно, захотите реализовать это, создав тип «обертка», который имеет Dictionary<TKey, Tuple<TValue, TValue>>.Затем вы должны написать индексатор, чтобы выбрать между двумя значениями.

1 голос
/ 26 сентября 2010

Я бы просто реализовал это в классе, который использует Dictionary<TKey, TValue[]> внутри.Таким образом, вы могли бы даже реализовать тип, чтобы иметь переменное число значений на ключ.

0 голосов
/ 26 сентября 2010

Этот код, приведенный ниже, решит часть проблемы со словарем и сделает рандомизацию настраиваемой, чтобы вы могли применять такой псевдослучайный уровень, который соответствует вашим потребностям.(или просто зашифруйте его вместо использования функтора)

public class DoubleDictionary<K, T> : IEnumerable<KeyValuePair<K, T>>
{
    private readonly Dictionary<K, Tuple<T, T>> _dictionary = new Dictionary<K, Tuple<T, T>>();
    private readonly Func<bool> _getFirst;

    public DoubleDictionary(Func<bool> GetFirst) {
        _getFirst = GetFirst;
    }

    public void Add(K Key, Tuple<T, T> Value) {
        _dictionary.Add(Key, Value);
    }

    public T this[K index] {
        get {
            Tuple<T, T> pair = _dictionary[index];
            return GetValue(pair);
        }
    }

    private T GetValue(Tuple<T, T> Pair) {
        return _getFirst() ? Pair.Item1 : Pair.Item2;
    }

    public IEnumerable<K> Keys {
        get {
            return _dictionary.Keys;
        }
    }

    public IEnumerable<T> Values {
        get {
            foreach (var pair in _dictionary.Values) {
                yield return GetValue(pair);
            }
        }
    }

    IEnumerator<KeyValuePair<K, T>> IEnumerable<KeyValuePair<K, T>>.GetEnumerator()  {
        foreach (var pair in _dictionary)  {
            yield return new KeyValuePair<K, T>(pair.Key, GetValue(pair.Value));
        }
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
        return ((IEnumerable<KeyValuePair<K, T>>)this).GetEnumerator();
    }
}
0 голосов
/ 26 сентября 2010

Вы также можете написать метод расширения для словаря, чтобы вы могли создать что-то вроде этого:

IDictionary<string, Tuple<int, int>> doubleDictionary = new Dictionary<string, Tuple<int, int>>();


doubleDictionary.GetRandomValueForKey("A");

Тогда вы можете использовать это с любым словарем.

public static void GetRandomValueForKey(this Dictionary<string, Tuple<int, int>> dict, 
                                     string key)
{
    ... Code to return the value
}

^^, которое было написано на моей голове, так что извините, если это не так.

0 голосов
/ 26 сентября 2010

Использовать Tuple как тип значения словаря.

IDictionary<string, Tuple<int, int>> doubleDictionary = new Dictionary<string, Tuple<int, int>>();
// ...
int secondValue = doubleDictionary["A"].Item2;
...