Мой другой ответ верен для вопроса и был бы полезен во многих случаях, таких как получение информации о броске из пользовательских кубиков (каждый бросок кубика является случайным, независимым от других кубиков). Однако ваши комментарии звучат так, будто вы надеетесь получить ряд «уникальных» элементов из 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 для простого кода тасования. Если это все еще не совсем то, что вы искали, возможно, вы можете начать новый вопрос с более подробной информацией о том, что вы пытаетесь сделать.