如何访问列表中的随机项目?


233

我有一个ArrayList,我需要能够单击一个按钮,然后从该列表中随机选择一个字符串,并将其显示在消息框中。

我将如何去做?

Answers:


404
  1. Random某处创建类的实例。请注意,每次需要随机数时都不要创建新实例,这一点非常重要。您应该重用旧实例以实现生成数字的一致性。您可以在static某处有一个字段(请注意线程安全性问题):

    static Random rnd = new Random();
  2. 要求Random实例给您一个随机数,其中包含最大数量的项目ArrayList

    int r = rnd.Next(list.Count);
  3. 显示字符串:

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

有什么好的方法可以对此进行修改,以免重复输入数字?假设我想一次随机选择一张纸牌来洗牌,但是显然不能两次选择同一张纸牌。
2014年

7
@ McAdam331查找Fisher-Yates随机播放算法:en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
Mehrdad Afshari 2014年

2
应该使用“ rnd.Next(list.Count-1)”而不是“ rnd.Next(list.Count-1)”来避免访问元素最大值,该值可能超出基于0的索引范围?
B. Clay Shannon'2

22
@ B.ClayShannon否。Next(max)呼叫的上限是唯一的。
Mehrdad Afshari

1
如果列表为空怎么办?
tsu1980 '19

137

我通常使用这种扩展方法的小集合:

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>();

这些的复杂性是什么?IEnumerable的惰性性质是否意味着它不是O(N)?
戴夫·希利尔

17
每次您选择随机数时,此答案都会重新排列列表。返回随机索引值会更有效,尤其是对于大型列表。在PickRandom中使用它 return list[rnd.Next(list.Count)];
swax 2012年

这并不洗牌原始列表,它实际是另一个列表仍然可能不是效率好,如果名单是足够大的..上
nawfal

.OrderBy(。)不会创建另一个列表-它会创建IEnumerable <T>类型的对象,该对象以有序方式遍历原始列表。
2013年

5
GUID生成算法是不可预测的,但不是随机的。考虑Random改为持有静态实例。

90

你可以做:

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

美丽。在ASP.NET MVC 4.5中,使用列表,我必须将其更改为:list.OrderBy(x => Guid.NewGuid())。FirstOrDefault();
安迪·布朗

3
在大多数情况下都没有关系,但这可能比使用rnd.Next慢得多。OTOH可以在IEnumerable <T>上运行,而不仅仅是列表。
可溶性鱼

12
不确定随机性如何。指导是唯一的,不是随机的。
彭博

1
我认为此答案(和我的评论)很好地总结了该答案和@solvefish的注释的一个更好的扩展版本。

23

创建一个Random实例:

Random rnd = new Random();

获取一个随机字符串:

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

但是请记住,如果经常执行此操作,则应重新使用该Random对象。将其作为静态字段放入类中,以便仅初始化一次然后访问它。


20

或像这样的简单扩展类:

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>为此,请使用诸如或数组的索引集合。


3
.NET中的数组已经实现,IList因此不需要第二次重载。

3

为什么不:

public static T GetRandom<T>(this IEnumerable<T> list)
{
   return list.ElementAt(new Random(DateTime.Now.Millisecond).Next(list.Count()));
}

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
尽管此代码段可以解决问题,但提供说明确实有助于提高您的帖子质量。请记住,您将来会为读者回答这个问题,而这些人可能不知道您提出代码建议的原因。
gunr2171 2015年

3
我要说的是,maxValue方法的参数Next应该只是列表中的多个元素,而不是减一个,因为根据文档“ maxValue是随机数的唯一上限 ”。
David FerenczyRogožan2015年

1

我已经使用此ExtensionMethod一段时间了:

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;
}

你忘了添加Random类的实例
bafsar

1

我会建议采用其他方法,如果列表中项目的顺序在提取时并不重要(每个项目只能选择一次),那么List可以使用a ConcurrentBag作为线程安全的无序集合,而不是a 对象:

var bag = new ConcurrentBag<string>();
bag.Add("Foo");
bag.Add("Boo");
bag.Add("Zoo");

EventHandler:

string result;
if (bag.TryTake(out result))
{
    MessageBox.Show(result);
}

TryTake会尝试从无序集合提取一个“随机”的对象。


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); 

0

从JSON文件中随机打印国家名称。
模型:

public class Country
    {
        public string Name { get; set; }
        public string Code { get; set; }
    }

实施:

string filePath = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, @"..\..\..\")) + @"Data\Country.json";
            string _countryJson = File.ReadAllText(filePath);
            var _country = JsonConvert.DeserializeObject<List<Country>>(_countryJson);


            int index = random.Next(_country.Count);
            Console.WriteLine(_country[index].Name);

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.