我需要从马匹列表中选择随机对象。目前我正在尝试使用LINQ。我需要做的是用户选择他们想要的对象数量,并从列表中随机选择对象数量。
此处是我的代码:
Random rand = new Random();
//creates a list of horses that haven't yet been assigned to players
List<Horse> unassignedHorses = retrieveUnassignedHorses();
List<Horse> selectedHorses = unassignedHorses.OrderBy(m => rand.Next())
.Take(numberHorses)
.ToList();
我的问题是这是一个很好的方法,或者是一种更好的方式。
答案 0 :(得分:4)
当您想从集合中获取&#34; N个随机项时,可以使用两种通用方法。
您选择第二个选项(尽管您使用了一种低效且有偏见的方法)。
哪个最好,这取决于。首先,从技术上讲,第一个选项是O(无穷大),因为有可能一遍又一遍地随机选择相同的项目。如果你想谈论平均情况,它将成为一个有效的选择。
当您想要的项目数量占集合总大小的一小部分时,第一个选项最佳。如果您只想获得1%的收藏品,那么随机选择已经选择的商品的几率非常非常小。
另一方面,第二个选项,洗牌更好,如果你想要一个大百分比的集合中的项目,因为你做同样的工作量,无论你是否想要1项目或全部。如果您只想要集合中1%的项目,那么您最终会浪费一大堆努力来改变您根本不关心的数据。
现在,我们 想要做的事情是随机抽取集合中的前N个项目,但不会拖延剩余的所有项目。
有趣的是,这实际上很容易做到。改组列表的一个更优选的方法是从最高索引倒计数到最低值,选择当前索引下面的项目,并将其与当前索引交换。与排序不同,这不会引入偏差,与O(n * log(n))的排序不同,它不是O(n),更好的是,它的超级容易停止部分。所以如果我们实现这个改组算法:
public static IEnumerable<T> Shuffle<T>(
this IEnumerable<T> source, Random random)
{
var list = source.ToList();
for (int i = list.Count; i > 0; i--)
{
var index = random.Next(i);
var temp = list[index];
list[index] = list[i - 1];
list[i - 1] = temp;
yield return temp;
}
}
我们现在可以将您的解决方案写成:
var selectedHorses = unasignedHorses.Shuffle(rand).Take(numberHorses);
答案 1 :(得分:0)
int numberHorses = 3; //or some user input
Random r = new Random();
List<Horse> unassignedHorses = retriveUnassignedHorses();
List<Horse> assignedHorses = new List<Horse>();
do
{
int rIint = r.Next(0, unnasignedHorses.Count);
if(!assignedHorses.Contains(unassignedHorses[rInt]))
{
assignedHorses.Add(unassignedHorses[rInt]);
}
} (while assignedHorses.Count != numberHorses);
就像我在评论中说的那样,如果你现在的方式有效并且对你有意义,那么为什么要改变呢?我还没有尝试过这段代码,但我认为这样的事情可以完成你正在寻找的东西。这可能看起来过于复杂,但这就是我的解决方案似乎如何开始然后我最终简化它们......
答案 2 :(得分:-2)
所以你想从列表中选择随机对象
我想这可能是完成的事情:
int r = rnd.Next(numberHorses.Count);
Horse selectedHorse = unnasignedHorses[r];