c# - parse - Entrée aléatoire du dictionnaire




c# dictionary parse (6)

Ce ne sera pas très rapide, mais cela devrait fonctionner:

Random rand = new Random();
Dictionary dict = GetDictionary();
return dict.Skip(rand.Next(dict.Count)).First().Value;

Quel est le meilleur moyen d'obtenir une entrée aléatoire à partir d'un dictionnaire en c #?

J'ai besoin d'obtenir un certain nombre d'objets aléatoires du dictionnaire à afficher sur une page, mais je ne peux pas utiliser ce qui suit car les dictionnaires ne sont pas accessibles par index:

Random rand = new Random();
Dictionary< string, object> dict = GetDictionary();
return dict[rand.Next()];

Aucune suggestion?


De votre dictionnaire ...

Dictionary<string, int> dict = new Dictionary<string, object>()

vous pouvez créer une liste complète des clés ...

List<string> keyList = new List<string>(dict.Keys);

puis sélectionnez une clé aléatoire dans votre liste.

Random rand = new Random();
string randomKey = keyList[rand.Next(keyList.Count)];

Ensuite, renvoyez simplement l'objet aléatoire correspondant à cette clé.

return dict[randomKey];

Mon autre réponse est correcte pour la question, et serait utile dans de nombreux cas comme obtenir des informations de jet à partir de dés personnalisés (le jet de chaque dé est aléatoire, indépendant des autres dés). Cependant, vos commentaires donnent l'impression que vous espérez obtenir une série d'éléments «uniques» dans le Dictionary , un peu comme des cartes de jeu provenant d'un jeu de cartes. Une fois qu'une carte est distribuée, vous ne voulez plus jamais voir la même carte jusqu'à ce que vous la remodeliez. Dans ce cas, la meilleure stratégie dépendra exactement de ce que vous faites.

Si vous obtenez seulement quelques éléments d'un grand Dictionary , alors vous devriez être capable d'adapter mon autre réponse, en supprimant l'élément aléatoire de la liste chaque fois qu'un nouveau est récupéré. Vous voudrez probablement faire de la liste une LinkedList , car même s'il est plus lent de trouver un élément par son index, il est beaucoup moins cher de supprimer des éléments du milieu. Le code pour cela serait un peu plus compliqué, donc si vous êtes prêt à sacrifier des performances pour plus de simplicité, vous pouvez simplement faire ceci:

public IEnumerable<TValue> UniqueRandomValues<TKey, TValue>(IDictionary<TKey, TValue> dict)
{
    Random rand = new Random();
    Dictionary<TKey, TValue> values = new Dictionary<TKey, TValue>(dict);
    while(values.Count > 0)
    {
        TKey randomKey = values.Keys.ElementAt(rand.Next(0, values.Count));  // hat tip @yshuditelu 
        TValue randomValue = values[randomKey];
        values.Remove(randomKey);
        yield return randomValue;
    }
}

Si, d'un autre côté, vous prévoyez d'extraire un nombre important d'éléments de votre dictionnaire (c'est-à-dire plus que le log (n) de votre deck), vous feriez mieux de brouiller tout votre deck , puis en tirant par le haut:

public IEnumerable<TValue> UniqueRandomValues<TKey, TValue>(IDictionary<TKey, TValue> dict)
{
    // Put the values in random order
    Random rand = new Random();
    LinkedList<TValue> values = new LinkedList<TValue>(from v in dict.Values
                                                       orderby rand.Next()
                                                       select v);
    // Remove the values one at a time
    while(values.Count > 0)
    {
        yield return values.Last.Value;
        values.RemoveLast();
    }
}

Le crédit va à ookii.org pour le code de brassage simple. Si ce n'est pas tout à fait ce que vous cherchiez, vous pouvez peut-être commencer une nouvelle question avec plus de détails sur ce que vous essayez de faire.


Quelque chose comme:

Random rand = new Random();
Dictionary dict = GetDictionary();
var k = dict.Keys.ToList()[rand.Next(dict.Count)];
return dict[k];

Une solution simple consisterait à utiliser la méthode d'extension ToList() et à utiliser l'index de la liste.

Si vous avez juste besoin des valeurs ou des clés (pas la paire clé / valeur), renvoyez ces collections du dictionnaire et utilisez aussi ToList() .

        Random rand = new Random();
        Dictionary<string, object> dict = GetDictionary();
        var k = dict.ToList()[rand.Next(dict.Count)];
        // var k = dict.Values.ToList()[rand.Next(dict.Count)];
        // var k = dict.Keys.ToList()[rand.Next(dict.Count)];

        Console.WriteLine("Random dict pair {0} = {1}", k.Key, k.Value);

Mise à jour pour utiliser les génériques, soyez encore plus rapide, et avec une explication de la raison pour laquelle cette option est plus rapide.

Cette réponse est similaire aux autres réponses, mais puisque vous avez dit que vous avez besoin d'un certain nombre d'éléments aléatoires, ce sera plus performant:

public IEnumerable<TValue> RandomValues<TKey, TValue>(IDictionary<TKey, TValue> dict)
{
    Random rand = new Random();
    List<TValue> values = Enumerable.ToList(dict.Values);
    int size = dict.Count;
    while(true)
    {
        yield return values[rand.Next(size)];
    }
}

Vous pouvez utiliser cette méthode comme ceci:

Dictionary<string, object> dict = GetDictionary();
foreach (object value in RandomValues(dict).Take(10))
{
    Console.WriteLine(value);
}

Cela a amélioré les performances par rapport aux autres réponses (y compris la réponse de yshuditelu).

  1. Il n'est pas nécessaire de créer une nouvelle collection de tous les éléments du dictionnaire chaque fois que vous voulez récupérer une nouvelle valeur aléatoire. C'est vraiment un gros problème si votre dictionnaire contient beaucoup d'éléments.
  2. Il ne doit pas effectuer une recherche basée sur la clé du dictionnaire chaque fois que vous récupérez une valeur aléatoire. Pas aussi gros que le n ° 1, mais il est encore deux fois plus rapide de cette façon.

Mes tests montrent qu'avec 1000 objets dans le dictionnaire, cette méthode est environ 70 fois plus rapide que les autres méthodes suggérées.





dictionary