C# 字典中的随机条目

C# 字典中的随机条目,c#,dictionary,C#,Dictionary,在c#中,从字典中获取随机条目的最佳方法是什么 我需要从字典中获取一些随机对象以显示在页面上,但是我不能使用以下内容,因为索引无法访问字典: Random rand = new Random(); Dictionary< string, object> dict = GetDictionary(); return dict[rand.Next()]; Random rand=new Random(); Dictionarydict=GetDictionary(); 返回dict[r

在c#中,从字典中获取随机条目的最佳方法是什么

我需要从字典中获取一些随机对象以显示在页面上,但是我不能使用以下内容,因为索引无法访问字典:

Random rand = new Random();
Dictionary< string, object> dict = GetDictionary();
return dict[rand.Next()];
Random rand=new Random();
Dictionarydict=GetDictionary();
返回dict[rand.Next()];
有什么建议吗?

比如:

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

我认为唯一的方法是首先创建一个单独的KeyValuePairs列表。

一个简单的解决方案是使用扩展方法并使用列表的索引

如果您只需要值或键(而不是键/值对),请从字典返回这些集合并使用它们

Random rand=new Random();
Dictionary 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)];
WriteLine(“随机dict对{0}={1}”,k.键,k.值);

这不会太快,但应该可以:

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

如果您使用的是.net 3.5,Enumerable有一个扩展方法,允许您执行以下操作:

return dict.ElementAt(rand.Next(0, dict.Count)).Value;

从你的字典

Dictionary<string, int> dict = new Dictionary<string, object>()
然后简单地返回与该键匹配的随机对象

return dict[randomKey];
更新为使用泛型,速度更快,并解释了为什么此选项更快

这个答案与其他回答类似,但因为你说你需要“一些随机元素”,这将更有效:

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)];
    }
}
公共IEnumerable随机值(IDictionary dict)
{
Random rand=新的Random();
列表值=可枚举的ToList(dict.values);
整数大小=数字计数;
while(true)
{
收益率返回值[rand.Next(size)];
}
}
您可以这样使用此方法:

Dictionary<string, object> dict = GetDictionary();
foreach (object value in RandomValues(dict).Take(10))
{
    Console.WriteLine(value);
}
Dictionary dict=GetDictionary();
foreach(随机值中的对象值(dict.Take)(10))
{
控制台写入线(值);
}
这比其他响应(包括yshuditelu的响应)有性能改进

  • 每次您想要获取新的随机值时,它不必创建字典所有元素的新集合。如果你的字典里有很多元素,这真是一件大事
  • 它不必在每次获取随机值时根据字典的键执行查找。虽然没有#1那么重要,但这样的速度还是快了一倍

  • 我的测试表明,对于字典中的1000个对象,这种方法比其他建议的方法快70倍左右。

    我的另一个答案对这个问题是正确的,并且在许多情况下非常有用,比如从自定义骰子中获取掷骰信息(每个骰子的掷骰是随机的,与其他骰子无关)。然而,您的评论听起来似乎是希望从
    字典中获得一系列“独特”元素,有点像从一副牌堆中处理卡片。一旦发了一张牌,在重新洗牌之前,你再也不想看到同一张牌了。在这种情况下,最佳策略将完全取决于你在做什么

    如果您只从大型
    词典中获取了几个元素,那么您应该能够调整我的另一个答案,即每次检索到新的元素时从列表中删除随机元素。您可能还想将列表制作成一个
    LinkedList
    ,因为即使通过索引查找项目会比较慢,但从中间删除元素的成本也要低得多。这方面的代码会稍微复杂一些,因此如果您愿意为了简单而牺牲一些性能,您可以这样做:

    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;
        }
    }
    
    public IEnumerable UniqueRandomValues(IDictionary dict)
    {
    Random rand=新的Random();
    字典值=新字典(dict);
    而(values.Count>0)
    {
    TKey randomKey=values.Keys.ElementAt(rand.Next(0,values.Count));//hat tip@yshuditelu
    TValue randomValue=值[randomKey];
    移除(随机键);
    收益率;收益率;
    }
    }
    
    另一方面,如果您计划从字典中提取大量元素(即,处理的内容超过“组”的log(n)),则最好先洗牌整个组,然后从顶部提取:

    public IEnumerable<TValue> UniqueRandomValues<TKey, TValue>(IDictionary<TKey, TValue> dict)
    {
        // Put the values in random order
        Random rand = new Random();
        LinkedList<TValue> values = new(dict.Values.OrderBy(_ => rand.Next());
        // Remove the values one at a time
        while(values.Count > 0)
        {
            yield return values.Last.Value;
            values.RemoveLast();
        }
    }
    
    public IEnumerable UniqueRandomValues(IDictionary dict)
    {
    //将这些值按随机顺序排列
    Random rand=新的Random();
    LinkedList values=new(dict.values.OrderBy(=>rand.Next());
    //一次删除一个值
    而(values.Count>0)
    {
    收益率返回值.Last.Value;
    value.RemoveLast();
    }
    }
    
    简单的洗牌代码值得称赞。如果这仍然不是您想要的,也许您可以开始一个新的问题,提供有关您尝试执行的操作的更多详细信息。

    公共静态类DictionaryExtensions
    
    public static class DictionaryExtensions
    {
        public static TKey[] Shuffle<TKey, TValue>(
           this System.Collections.Generic.Dictionary<TKey, TValue> source)
        {
            Random r = new Random();
            TKey[] wviTKey = new TKey[source.Count];
            source.Keys.CopyTo(wviTKey, 0);
    
            for (int i = wviTKey.Length; i > 1; i--)
            {
                int k = r.Next(i);
                TKey temp = wviTKey[k];
                wviTKey[k] = wviTKey[i - 1];
                wviTKey[i - 1] = temp;
            }
    
            return wviTKey;
        }
    }
    
    { 公共静态TKey[]洗牌( 此System.Collections.Generic.Dictionary(源代码) { 随机r=新随机(); TKey[]wviTKey=newtkey[source.Count]; source.Keys.CopyTo(wviTKey,0); 对于(int i=wviTKey.Length;i>1;i--) { int k=r.Next(i); TKey temp=wviTKey[k]; wviTKey[k]=wviTKey[i-1]; wviTKey[i-1]=温度; } 返回wviTKey; } }
    样品
    //使用
    System.Collections.Generic.Dictionary myDictionary=新的System.Collections.Generic.Dictionary();
    //添加(myObjectKey1,myObjectValue1);//示例
    //添加(myObjectKey2,myObjectValue2);//示例
    //添加(myObjectKey3,myObjectValue3);//示例
    //添加(myObjectKey4,myObjectValue4);//示例
    //var myShufledKeys=myDictionary.Shuffle();//示例
    
    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;
        }
    }
    
    public IEnumerable<TValue> UniqueRandomValues<TKey, TValue>(IDictionary<TKey, TValue> dict)
    {
        // Put the values in random order
        Random rand = new Random();
        LinkedList<TValue> values = new(dict.Values.OrderBy(_ => rand.Next());
        // Remove the values one at a time
        while(values.Count > 0)
        {
            yield return values.Last.Value;
            values.RemoveLast();
        }
    }
    
    public static class DictionaryExtensions
    {
        public static TKey[] Shuffle<TKey, TValue>(
           this System.Collections.Generic.Dictionary<TKey, TValue> source)
        {
            Random r = new Random();
            TKey[] wviTKey = new TKey[source.Count];
            source.Keys.CopyTo(wviTKey, 0);
    
            for (int i = wviTKey.Length; i > 1; i--)
            {
                int k = r.Next(i);
                TKey temp = wviTKey[k];
                wviTKey[k] = wviTKey[i - 1];
                wviTKey[i - 1] = temp;
            }
    
            return wviTKey;
        }
    }
    
                // Using
                System.Collections.Generic.Dictionary<object, object> myDictionary = new System.Collections.Generic.Dictionary<object, object>();
                // myDictionary.Add(myObjectKey1, myObjectValue1); // Sample
                // myDictionary.Add(myObjectKey2, myObjectValue2); // Sample
                // myDictionary.Add(myObjectKey3, myObjectValue3); // Sample
                // myDictionary.Add(myObjectKey4, myObjectValue4); // Sample
    
                // var myShufledKeys = myDictionary.Shuffle(); // Sample
                // var myShufledValue = myDictionary[myShufledKeys[0]]; // Sample
    
                // Easy Sample
                var myObjects = System.Linq.Enumerable.Range(0, 4);
                foreach(int i in myObjects)
                    myDictionary.Add(i, string.Format("myValueObjectNumber: {0}", i));
    
                var myShufledKeys = myDictionary.Shuffle();
                var myShufledValue = myDictionary[myShufledKeys[0]];