从字典中随机input
什么是最好的方式来从一个字典在C#中随机input?
我需要从fictionary中获取一些随机对象以显示在页面上,但是我不能使用:
Random rand = new Random(); Dictionary< string, object> dict = GetDictionary(); return dict[rand.Next()];
因为索引无法访问字典。
有什么build议么?
更新为使用generics,更快,并解释为什么这个选项更快。
这个答案类似于其他答案,但是由于你说你需要“一些随机元素”,这将是更高性能的:
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的回应)有性能改善。
- 每次你想要获取一个新的随机值时,不需要为所有的字典元素创build一个新的集合。 如果你的字典里有很多元素,这真是一件大事。
- 每次获取一个随机值时,不必根据Dictionary的键值执行查找。 虽然没有第一名那么重要,但是这样的速度仍然快了一倍。
我的testing显示,在字典中有1000个对象,这个方法比其他build议的方法快70倍。
如果您使用.net 3.5,Enumerable有一个扩展方法ElementAt ,它可以让你做到:
return dict.ElementAt(rand.Next(0, dict.Count)).Value;
从你的字典里
Dictionary<string, int> dict = new Dictionary<string, object>()
你可以创build一个完整的键列表 …
List<string> keyList = new List<string>(dict.Keys);
然后从列表中select一个随机密钥 。
Random rand = new Random(); string randomKey = keyList[rand.Next(keyList.Count)];
然后只需返回与该键匹配的随机对象 。
return dict[randomKey];
我的其他答案对于这个问题是正确的,并且在许多情况下是有用的,比如从习惯骰子获取掷骰信息(每个骰子是随机的,独立于其他骰子)。 然而,你的意见听起来像你可能希望从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为简单的洗牌代码。 如果这还不是你所期望的,那么也许你可以开始一个新的问题,提供更多关于你想要做什么的细节。
就像是:
Random rand = new Random(); Dictionary dict = GetDictionary(); var k = dict.Keys.ToList()[rand.Next(dict.Count)]; return dict[k];
这不会非常快,但它应该工作:
Random rand = new Random(); Dictionary dict = GetDictionary(); return dict.Skip(rand.Next(dict.Count)).First().Value;
一个简单的解决scheme是使用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);
我相信唯一的办法是先创build一个单独的KeyValuePairs列表。
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]];