C# 字典中的随机条目
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1028136/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Random entry from dictionary
提问by Ed James
What is the best way to get a random entry from a Dictionary in c#?
从 C# 中的字典中获取随机条目的最佳方法是什么?
I need to get a number of random objects from the dictionary to display on a page, however I cannot use the following as dictionaries cannot be accessed by index:
我需要从字典中获取一些随机对象以显示在页面上,但是我不能使用以下内容,因为索引无法访问字典:
Random rand = new Random();
Dictionary< string, object> dict = GetDictionary();
return dict[rand.Next()];
Any suggestions?
有什么建议?
采纳答案by StriplingWarrior
Updated to use generics, be even faster, and with an explanation of why this option is faster.
更新为使用泛型,速度更快,并解释为什么此选项更快。
This answer is similar to the other responses, but since you said you need "a number of random elements" this will be more 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)];
}
}
You can use this method like so:
您可以像这样使用此方法:
Dictionary<string, object> dict = GetDictionary();
foreach (object value in RandomValues(dict).Take(10))
{
Console.WriteLine(value);
}
This has performance improvements over the other responses (including yshuditelu's response).
这比其他响应(包括 yshuditelu 的响应)有性能改进。
- It doesn't have to create a new collection of all of the dictionary's elements each time you want to fetch a new random value. This is a really big deal if your dictionary has a lot of elements in it.
- It doesn't have to perform a lookup based on the Dictionary's key each time you fetch a random value. Not as big a deal as #1, but it's still over twice as fast this way.
- 每次您想要获取新的随机值时,它都不必创建所有字典元素的新集合。如果你的字典中有很多元素,这真的很重要。
- 每次获取随机值时,它不必根据字典的键执行查找。没有 #1 大,但这种方式仍然快两倍多。
My tests show that with 1000 objects in the dictionary, this method goes about 70 times faster than the other suggested methods.
我的测试表明,对于字典中的 1000 个对象,此方法比其他建议的方法快 70 倍。
回答by Henk Holterman
Something like:
就像是:
Random rand = new Random();
Dictionary dict = GetDictionary();
var k = dict.Keys.ToList()[rand.Next(dict.Count)];
return dict[k];
回答by Groo
I believe the only way is to create a separate list of KeyValuePairs first.
我相信唯一的方法是首先创建一个单独的 KeyValuePairs 列表。
回答by bruno conde
An easy solution would be to use the ToList()
extension method and use the index of the list.
一个简单的解决方案是使用ToList()
扩展方法并使用列表的索引。
If you just need the values or the keys (not the key/value pair) return these collections from the dictionary and use ToList()
as well.
如果您只需要值或键(不是键/值对),请从字典中返回这些集合并使用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);
回答by Jonathan Rupp
This won't be terribly fast, but it should work:
这不会非常快,但它应该工作:
Random rand = new Random();
Dictionary dict = GetDictionary();
return dict.Skip(rand.Next(dict.Count)).First().Value;
回答by Timothy Carter
回答by Robert Cartaino
From your dictionary...
从你的字典...
Dictionary<string, int> dict = new Dictionary<string, object>()
you can create a complete list of keys...
您可以创建完整的密钥列表...
List<string> keyList = new List<string>(dict.Keys);
and then select a random keyfrom your list.
然后从列表中选择一个随机密钥。
Random rand = new Random();
string randomKey = keyList[rand.Next(keyList.Count)];
Then simply return the random objectmatching that key.
然后简单地返回匹配该键的随机对象。
return dict[randomKey];
回答by StriplingWarrior
My other answer is correct for the question, and would be useful in many cases like getting roll information from custom dice (each die's roll is random, independent of the other dice). However, your comments make it sound like you might be hoping to get a series of "unique" elements out of the Dictionary
, sort of like dealing cards from a deck. Once a card is dealt, you never want to see the same card again until a re-shuffle. In that case, the best strategy will depend on exactly what you're doing.
我的另一个答案对这个问题是正确的,并且在许多情况下都很有用,比如从自定义骰子获取掷骰信息(每个骰子的掷骰是随机的,独立于其他骰子)。但是,您的评论听起来好像您可能希望从 中获得一系列“独特”元素Dictionary
,有点像从一副牌中发牌。一旦发了一张牌,你就再也不想看到同一张牌,直到重新洗牌。在这种情况下,最佳策略将取决于您正在做什么。
If you're only getting a few elements out of a large Dictionary
, then you should be able to adapt my other answer, removing the random element from the list each time a new one is retrieved. You'll probably also want to make the list into a LinkedList
, because even though it'll be slower to find an item by its index, it's much less expensive to remove elements from the middle of it. The code for this would be a little more complicated, so if you're willing to sacrifice some performance for simplicity you could just do this:
如果您只从 large 中获取几个元素Dictionary
,那么您应该能够调整我的另一个答案,每次检索到新元素时从列表中删除随机元素。您可能还想将列表变成 a 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;
}
}
If, on the other hand, you're planning to pull a significant number of elements from your dictionary (i.e. dealing out more than log(n) of your "deck"), you'll be better off just shuffling your entire deck first, and then pulling from the top:
另一方面,如果您打算从字典中提取大量元素(即处理多于 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();
}
}
Credit goes to ookii.orgfor the simple shuffling code. If this still isn't quite what you were looking for, perhaps you can start a new question with more details about what you're trying to do.
幸得ookii.org很简单洗牌代码。如果这仍然不是您想要的,也许您可以开始一个新问题,其中包含有关您要执行的操作的更多详细信息。
回答by user3245067
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;
}
}
Sample
样本
// 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]];