从数组中随机选择字符串

30

如何从我的数组中随机选择一个字符串,但不重复选择同一个字符串。

string[] names = { "image1.png", "image2.png", "image3.png", "image4.png", "image5.png" };

这是可能的吗?我在考虑使用

return strings[random.Next(strings.Length)];

但是这种方法有可能返回相同的字符串两次。我是否理解错误?是否应该使用像List这样的东西来完成这个任务?欢迎任何反馈。


5
听起来你想要对数组进行洗牌,然后按正常顺序迭代数组。在 Stack Overflow 上有很多关于洗牌的问题。 - Jon Skeet
1
@Atrljoe - 你明白返回两次相同的字符串会得到随机结果吗?如果你不想得到相同的结果,那么你想要的就不能被描述为随机结果。 - Security Hound
当然,它会是随机的。它不会是一系列独立事件,但它仍然是随机的。 - CodesInChaos
@ramhound 我明白这不是完全随机的,但在这种情况下,如果我要求用户选择一张图片,而它返回所有相同的图片(理论上可能性非常小),那么用户就没有选择。我不需要它完美,只需要足够让我得到看起来随机的结果。 - atrljoe
我已经回答了这个问题:从一个字符串数组中获取随机值的最快方法。 - mr.memo
8个回答

41

最简单的方法(但对于大型列表来说速度较慢)是使用可调整大小的容器,比如List,并在选择元素后删除它。例如:

var names = new List<string> { "image1.png", "image2.png", "image3.png", "image4.png", "image5.png" };

int index = random.Next(names.Count);
var name = names[index];
names.RemoveAt(index);
return name;

如果列表为空,则所有值都已被选中。

一种更快的方法(特别是如果您的列表很长)是在列表上使用洗牌算法。然后,您可以逐个弹出值。这样做会更快,因为从List的末尾删除比从中间删除要快得多。至于洗牌,您可以参考此问题以获得更多详细信息。


1
@samb8s 是的,但我更快 :) - Etienne de Martel
2
请注意,如果列表很长,则这可能是一个不好的想法。从长列表的开头删除一个项目必须移动其后面的所有项目。 - Eric Lippert

37

尝试使用下面的代码

string[] Titles = { "Excellent", "Good", "Super", "REALLY GOOD DOCTOR!", "THANK YOU!", "THE BEST", "EXCELLENT PHYSICIAN", "EXCELLENT DOCTOR" };

comments_title.Value=Titles[new Random().Next(0,Titles.Length) ] ;

4
以后在您的帖子中加入更多描述。不过,这是个好主意! :) - davehale23
我一直认为所有的评论都是真实的,而且那些得到好评的产品确实很好。 - Zurechtweiser
1
如果选择最大值(Titles.Length),这将导致IndexOutOfRangeException。否则它可以正常工作。(只需使用Titles.Length - 1) - Gober
3
@Gober上限是排除在外的,所以这不会成为问题:https://msdn.microsoft.com/zh-cn/library/2dx6wyd4(v=vs.110).aspx - Ben Visness
为什么我生成的数字总是相同的? - Trung
不要在for循环内部使用new Random(),因为它会在调用太早的情况下每次都给你相同的数字。在循环外声明一个Random对象,并在循环内使用该引用。 - Vishnu Babu

5
您可以先对数组进行洗牌,然后简单地迭代洗牌后的数组。相比使用基于 RemoveAt 的实现,这样做的优点在于时间复杂度为 O(n),而不是 O(n^2)。当然,对于短数组来说这并不重要。
请参考 Jon Skeet 在以下问题的回答,了解一个好的(所有顺序都是等可能的)洗牌实现:Is using Random and OrderBy a good shuffle algorithm?

2

最好的方法就是创建一个副本列表,然后在随机选择字符串时,您可以从副本列表中删除它,以便您不能选择两次。


2
您可以使用以下逻辑:
1)在等于数组长度的范围内选择一个随机整数。您可以使用System.Random类来实现。
2)使用对应于该数组索引的字符串。
3)从数组中删除该索引处的项目(使用列表可能更容易)。
然后您可以再次选择,相同的字符串将不会出现。该数组将缩短一个元素。

1
使用以下实用方法。
public static class ListExtensions
{
    public static T PickRandom<T>(this List<T> enumerable)
    {
        int index = new Random().Next(0, enumerable.Count());
        return enumerable[index];
    }
}

然后调用以下方式。
string[] fruitsArray = { "apple", "orange"};
string inputString = fruitsArray.ToList().PickRandom();

1
你需要跟踪你所使用过的数字,最好是在一个List中,如果你不想要或者不能修改原始数组。使用一个while循环来检查它是否已经被使用,然后将其添加到“used”列表中。

4
假设原始列表中有一千个项目,而“已使用”列表中有九百九十九个项目。你的计划是不断生成随机数,直到命中其中一个在一千个项目中的数?这个选择算法会变得越来越慢。对于更长的列表来说,这是一个糟糕的算法。 - Eric Lippert

1
//SET LOWERLIMIT
cmd = new SqlCommand("select min(sysid) as lowerlimit from users", cs);
int _lowerlimit = (int) cmd.ExecuteScalar();
lowerlimit = _lowerlimit;

//SET UPPERLIMIT
cmd = new SqlCommand("select max(sysid) as upperlimit from users", cs);
int _upperlimit = (int) cmd.ExecuteScalar();
upperlimit = _upperlimit;

//GENERATE RANDOM NUMBER FROM LOWERLIMIT TO UPPERLIMIT
Random rnd = new Random();
int randomNumber = rnd.Next(lowerlimit, upperlimit+1);

//DISPLAY OUTPUT
txt_output.Text += randomNumber;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接