2010-01-07 2 views

ответ

289
  1. Создайте экземпляр класса Random. Обратите внимание, что очень важно не создавать новый экземпляр каждый раз, когда вам нужно случайное число. Вы должны повторно использовать старый экземпляр для достижения однородности в сгенерированных числах. Вы можете иметь static поля где-то (быть осторожными о вопросах безопасности нити):

    static Random rnd = new Random(); 
    
  2. Спросите экземпляр Random, чтобы дать вам случайное число с максимумом числа элементов в ArrayList:

    int r = rnd.Next(list.Count); 
    
  3. Показать строку:

    MessageBox.Show((string)list[r]); 
    
+0

Есть ли хороший способ изменить это, чтобы число не повторялось? Предположим, я хотел перетасовать колоду карт, случайно выбрав один за раз, но, очевидно, не может выбрать одну и ту же карту дважды. – AdamMc331

+5

@ McAdam331 Посмотрите алгоритм Fisher-Yates Shuffle: http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle –

+2

Если это «rnd.Next (list.Count-1)» вместо «rnd» .Next (list.Count) ", чтобы избежать доступа к элементу max, который был бы за пределами индекса, основанного на предположении 0. –

15

Создание Random экземпляра:

Random rnd = new Random(); 

Fetch случайную строку:

string s = arraylist[rnd.Next(arraylist.Count)]; 

Помните, что если вы делаете это часто вы должны повторно использовать Random объект. Поместите его как статическое поле в класс, чтобы он инициализировался только один раз, а затем доступ к нему.

103

Я обычно использую этот небольшой набор методов расширения:

public static class EnumerableExtension 
{ 
    public static T PickRandom<T>(this IEnumerable<T> source) 
    { 
     return source.PickRandom(1).Single(); 
    } 

    public static IEnumerable<T> PickRandom<T>(this IEnumerable<T> source, int count) 
    { 
     return source.Shuffle().Take(count); 
    } 

    public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source) 
    { 
     return source.OrderBy(x => Guid.NewGuid()); 
    } 
} 

Для сильно типизированного списка, это позволит вам написать:

var strings = new List<string>(); 
var randomString = strings.PickRandom(); 

Если все у вас есть это ArrayList, вы можете бросить это:

var strings = myArrayList.Cast<string>(); 
+0

Какова их сложность? ленивая природа IEnumerable означает, что это не O (N)? –

+8

Этот ответ повторно перетасовывает список каждый раз, когда вы выбираете случайное число. Было бы гораздо эффективнее вернуть значение случайного индекса, особенно для больших списков. Используйте это в PickRandom - 'return list [rnd.Next (list.Count)];' – swax

+0

Это не перетасовывает исходный список, но делает его в другом списке, который по-прежнему может быть неэффективным, если список достаточно велик .. – nawfal

70

Вы можете сделать:

list.OrderBy(x => Guid.NewGuid()).FirstOrDefault() 
+0

Красивые. В ASP.NET MVC 4.5, uisng список, мне пришлось изменить это на: list.OrderBy (x => Guid.NewGuid()). FirstOrDefault(); –

+2

В большинстве случаев это не имеет значения, но это, вероятно, намного медленнее, чем использование rnd.Next. OTOH он будет работать на IEnumerable , а не только на списки. – solublefish

+8

Не уверен, насколько это случайность. Гиды уникальны, а не случайны. – pomber

2
ArrayList ar = new ArrayList(); 
     ar.Add(1); 
     ar.Add(5); 
     ar.Add(25); 
     ar.Add(37); 
     ar.Add(6); 
     ar.Add(11); 
     ar.Add(35); 
     Random r = new Random(); 
     int index = r.Next(0,ar.Count-1); 
     MessageBox.Show(ar[index].ToString()); 
+3

Хотя этот фрагмент кода может решить вопрос, [включая объяснение] (http://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) действительно помогает улучшить качество вашего сообщения. Помните, что вы отвечаете на вопрос читателей в будущем, и эти люди могут не знать причин вашего предложения кода. – gunr2171

+2

Я бы сказал, что параметр 'maxValue' метода' Next' должен быть всего лишь несколькими элементами в списке, а не минусом, потому что согласно документации «* maxValue является ** исключительной верхней границей ** случайное число*". –

9

Или просто класс расширения, как это:

public static class CollectionExtension 
{ 
    private static Random rng = new Random(); 

    public static T RandomElement<T>(this IList<T> list) 
    { 
     return list[rng.Next(list.Count)]; 
    } 

    public static T RandomElement<T>(this T[] array) 
    { 
     return array[rng.Next(array.Length)]; 
    } 
} 

Тогда просто позвоните:

myList.RandomElement(); 

Работы для массивов, а также.

Я бы не позвонил OrderBy(), поскольку он может быть дорогим для больших коллекций. Используйте индексированные коллекции, например List<T>, или массивы для этой цели.

+1

Массивы в .NET уже реализуют 'IList', поэтому вторая перегрузка не нужна. – Dai

0

Я использую этот метод расширение на некоторое время:

public static IEnumerable<T> GetRandom<T>(this IEnumerable<T> list, int count) 
{ 
    if (count <= 0) 
     yield break; 
    var r = new Random(); 
    int limit = (count * 10); 
    foreach (var item in list.OrderBy(x => r.Next(0, limit)).Take(count)) 
     yield return item; 
} 
+0

Вы забыли добавить экземпляр Random class – bafsar

0

мне нужно больше деталь вместо одного. Итак, я написал:

public static TList GetSelectedRandom<TList>(this TList list, int count) 
     where TList : IList, new() 
{ 
    var r = new Random(); 
    var rList = new TList(); 
    while (count > 0 && list.Count > 0) 
    { 
     var n = r.Next(0, list.Count); 
     var e = list[n]; 
     rList.Add(e); 
     list.RemoveAt(n); 
     count--; 
    } 

    return rList; 
} 

При этом, вы можете получить элементы, сколько вы хотите, как случайно, как это:

var _allItems = new List<TModel>() 
{ 
    // ... 
    // ... 
    // ... 
} 

var randomItemList = _allItems.GetSelectedRandom(10); 
2

Почему нет:

public static T GetRandom<T>(this IEnumerable<T> list) 
{ 
    return list.ElementAt(new Random(DateTime.Now.Millisecond).Next(list.Count())); 
} 
Смежные вопросы