2010-09-26 107 views
2

我需要创建一个字典,每个键有2个值,它必须以相同的概率返回2个值之一。双值字典返回任何一个特定的键的值

例子:

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

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

有趣的问题..你能一点就可以了扩大? – 2010-09-26 17:55:01

+0

当查找某个键时,它是否总是先返回第一个值,然后是第二个还是应该是随机的(这不违反概率要求)? – NullUserException 2010-09-26 17:56:37

回答

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

没有什么内置的框架,以做到这一点的,但你可能会希望通过创建有Dictionary<TKey, Tuple<TValue, TValue>>“包装”类来实现它。然后你会写一个索引器在这两个值之间进行适当的选择。

+0

这就是我想要建议的,但我被打败了。 – jimplode 2010-09-26 17:59:51

+0

@jimplode你不能击败Skeet – 2010-09-26 18:18:24

+1

@Skeet:总会有下次! ;) – jimplode 2010-09-26 18:19:21

0

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

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

“当查找某个键时,它是否总是首先返回第一个值,然后是第二个还是应该是随机的?” NO =) – ZAA 2010-09-26 17:59:33

+0

仍然需要一些工作来切换值。 – 2010-09-26 18:00:13

+0

要BlueCode:没有好处,因为它必须随机r without没有.item1或item2 – ZAA 2010-09-26 18:01:53

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 
} 

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

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(); 
+0

谢谢,我认为这对我来说是更好的解决方案! – ZAA 2010-09-26 19:08:30

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(); 
    } 
} 
相关问题