2010-09-26 31 views
2

Je dois créer un dictionnaire qui a 2 valeurs par clé, et il doit retourner l'une des 2 valeurs avec la même probabilité.Dictionnaire à deux valeurs qui renvoie l'une des valeurs pour une clé spécifique

Exemple:

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

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

Question intéressante .. Pourriez-vous un peu? –

+0

Lors de la recherche d'une clé, devrait-elle toujours retourner la première valeur en premier, puis la seconde ou devrait-elle être aléatoire (ce qui ne viole pas l'exigence de probabilité)? – NullUserException

Répondre

1

Je fait juste implémenter dans une classe qui utilise une Dictionary<TKey, TValue[]> interne. De cette façon, vous pouvez même implémenter le type pour avoir un nombre variable de valeurs par clé.

Comme:

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

Il n'y a rien inscrit dans le cadre de ce faire, mais vous auriez probablement envie de le mettre en œuvre en créant un type « enveloppe » qui avait une Dictionary<TKey, Tuple<TValue, TValue>>. Vous écririez alors un indexeur pour choisir de manière appropriée entre les deux valeurs.

+0

C'est ce que j'étais sur le point de suggérer mais j'ai été battu. – jimplode

+0

@jimplode Vous ne pouvez pas battre le Skeet –

+1

@Skeet: il y a toujours la prochaine fois !! ;) – jimplode

0

Utilisez Tuple comme type de valeur de dictionnaire.

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

"Lorsque vous recherchez une clé, devrait-elle toujours retourner la première valeur en premier, puis la seconde ou devrait-elle être aléatoire?" NO =) – ZAA

+0

Encore besoin de travail pour alterner entre les valeurs. –

+0

Pour BlueCode: pas bon, car il doit ruturn aléatoirement sans .item1 ou item2 – ZAA

0

Vous pouvez aussi écrire une méthode d'extension pour le dictionnaire, vous pouvez créer quelque chose comme ceci:

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


doubleDictionary.GetRandomValueForKey("A"); 

Ensuite, vous pouvez l'utiliser avec tout dictionnaire.

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

^^ qui a été écrit sur le dessus de ma tête, alors s'il vous plaît excusez-moi si c'est légèrement faux.

9

Il serait possible d'écrire une implémentation IDictionary<TKey, TValue> qui se comportait de cette manière, mais ce ne serait pas une bonne idée: la plupart des gens trouveraient un indexeur non déterministe pour une classe de collection très peu intuitif.

Au lieu de cela, je vous suggère à la place de la responsabilité valeur pour une clé, plutôt que le dictionnaire lui-même. Une option serait d'écrire un type personnalisé qui est capable de choisir parmi un ensemble de possibilités avec une probabilité égale. Par exemple:

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

Vous pouvez ensuite utiliser le dictionnaire comme celui-ci:

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

merci, je pense que c'est la meilleure solution pour moi! – ZAA

0

Ce ci-dessous le code permettra de résoudre la partie dictionnaire du problème et de faire la répartition aléatoire personnalisable afin que vous pouvez appliquer un niveau si pseudo-aléatoire qui convient à vos besoins. (Ou simplement coder en dur au lieu de l'utilisation d'un foncteur)

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