双值字典,返回特定键的任何值

时间:2010-09-26 17:52:23

标签: c# dictionary probability

我需要创建一个每个键有2个值的字典,它必须以相同的概率返回2个值中的一个。

示例:

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

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

6 个答案:

答案 0 :(得分:9)

有可能编写一个以这种方式运行的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();

答案 1 :(得分:7)

框架中没有内置任何东西,但您可能希望通过创建具有Dictionary<TKey, Tuple<TValue, TValue>>的“包装器”类型来实现它。然后,您将编写一个索引器,以便在两个值之间进行适当选择。

答案 2 :(得分:1)

我实际上只是在一个内部使用Dictionary<TKey, TValue[]>的类中实现它。这样你甚至可以实现类型,使每个键具有可变数量的值。

像:

class RandomDictionary<TKey, TValue>
{
    Dictionary<TKey, TValue[]> m_dict;
    Random m_random;

    public RandomDictionary()
    {
        m_dict = new Dictionary<TKey, TValue[]>();
        m_random = new Random();
    }

    public TValue this[TKey key]
    {
        get
        {
            TValue[] values = m_dict[key];
            return values[m_random.Next(0, values.Length)];
        }
    }

    public void Define(TKey key, params TValue[] values)
    {
        m_dict[key] = new TValue[values.Length];
        Array.Copy(values, m_dict[key], values.Length);
    }

    public bool TryGetValue(TKey key, out TValue value)
    {
        TValue[] values;
        if (!m_dict.TryGetValue(key, out values))
        {
            value = default(TValue);
            return false;
        }

        value = values[m_random.Next(0, values.Length)];
        return true;
    }
}

答案 3 :(得分:0)

使用元组作为字典值类型。

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

答案 4 :(得分:0)

您还可以为字典编写扩展方法,因此您可以创建如下内容:

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
}

^^这是我头顶写的,所以如果这有点不对,请原谅。

答案 5 :(得分:0)

以下代码将解决问题的字典部分并使随机化可自定义,以便您可以应用适合您需要的级别伪随机性。 (或者只是硬编码而不是使用仿函数)

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