C#の辞書からランダムなエントリを取得する最良の方法は何ですか?
ページに表示するには、辞書からいくつかのランダムなオブジェクトを取得する必要がありますが、辞書はインデックスでアクセスできないため、次のものを使用できません。
Random Rand = new Random();
Dictionary< string, object> dict = GetDictionary();
return dict[Rand.Next()];
助言がありますか?
ジェネリックを使用するために更新され、さらに高速になり、このオプションが高速である理由の説明付き
この回答は他の回答と似ていますが、「いくつかのランダムな要素」が必要だと言ったので、これはよりパフォーマンスが向上します。
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の応答を含む)よりもパフォーマンスが向上します。
私のテストでは、辞書に1000個のオブジェクトがある場合、このメソッドは他の推奨されるメソッドよりも約70倍速くなることが示されています。
.net 3.5を使用している場合、Enumerableには拡張メソッド ElementAt があり、これを行うことができます。
return dict.ElementAt(Rand.Next(0, dict.Count)).Value;
辞書から...
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];
私の他の答えは質問に対して正しいものであり、カスタムサイコロからロール情報を取得するなど、多くの場合に役立ちます(各サイコロのロールはランダムで、他のサイコロとは無関係です)。しかし、あなたのコメントは、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;
簡単な解決策は、 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);
唯一の方法は、最初に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]];