从字典中随机输入

时间:2009-06-22 16:24:28

标签: c# dictionary

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

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

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

有什么建议吗?

9 个答案:

答案 0 :(得分:45)

如果你使用.net 3.5,Enumerable有一个扩展方法ElementAt,你可以这样做:

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

答案 1 :(得分:42)

更新以使用泛型,更快,并解释为什么此选项更快。

这个答案与其他答案类似,但既然你说你需要“一些随机元素”,那么这个答案会更有效:

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

您可以像这样使用此方法:

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

与其他回复(包括yshuditelu的回复)相比,性能有所提升。

  1. 每次要获取新的随机值时,不必创建所有字典元素的新集合。如果您的词典中包含很多元素,这是一个非常重要的事情。
  2. 每次获取随机值时,不必基于Dictionary的键执行查找。不像#1那么大,但它的速度仍然是这个速度的两倍。
  3. 我的测试表明,在字典中有1000个对象,这种方法比其他建议的方法快70倍。

答案 2 :(得分:16)

从你的字典中......

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

您可以创建完整的键列表 ...

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

然后从列表中选择一个随机密钥

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

然后只需返回与该键匹配的随机对象

return dict[randomKey];

答案 3 :(得分:12)

我的另一个答案对于这个问题是正确的,并且在许多情况下都很有用,例如从自定义骰子获取滚动信息(每个骰子的滚动是随机的,独立于其他骰子)。但是,你的评论听起来好像你可能希望得到Dictionary中的一系列“独特”元素,有点像从牌组中发牌。一旦发卡,你再也不想看到同一张卡,直到重新洗牌。在这种情况下,最好的策略将取决于您正在做什么。

如果您只从大Dictionary中获取一些元素,那么您应该能够调整我的其他答案,每次检索到新元素时都会从列表中删除随机元素。您可能还希望将列表设置为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;
    }
}

另一方面,如果你计划从你的词典中提取大量元素(即处理超过你的“套牌”的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 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();
    }
}

对于简单的混洗代码,信用转到ookii.org。如果这仍然不是你想要的,也许你可以开始一个新问题,详细了解你正在尝试做什么。

答案 4 :(得分:3)

类似的东西:

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

答案 5 :(得分:2)

这不会非常快,但应该有效:

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

答案 6 :(得分:1)

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

如果您只需要值或键(不是键/值对),请从字典中返回这些集合,并使用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);

答案 7 :(得分:0)

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

答案 8 :(得分:0)

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