简体   繁体   English

使用LINQ从列表中选择多个对象

[英]Selecting multiple objects from a list using LINQ

I need to select random objects from a list of horses. 我需要从马匹列表中选择随机对象。 At the moment I'm trying to use LINQ. 目前,我正在尝试使用LINQ。 What I need to have happen is the user selects how many object they want and that number of object is randomly selected from the list. 我需要做的是,用户选择他们想要的对象数量,然后从列表中随机选择该对象数量。

Here is my code at the moment: 这是我目前的代码:

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

My question is this a good way of doing this or is an even better way. 我的问题是这样做的好方法,还是更好的方法。

There are two general approaches that you can use when you want to get "N random items from a collection". 当您要获取“来自集合的N个随机项目”时,可以使用两种通用方法。

  1. Choose a random item, check if it hasn't been chosen before, if it has been, choose a new one. 选择一个随机项目,检查之前是否尚未选择过,如果已经选择过,则选择一个新项目。
  2. Shuffle the entire collection, then grab the first N items. 随机整理整个集合,然后获取前N个项目。

You choose the second option (although you used an inefficient and biased method of doing so). 您选择第二个选项(尽管您使用的是效率低下且有偏见的方法)。

Which is best, well, that depends. 最好,这取决于。 First off, technically, the first option is O(infinity) because there is the possibility of randomly selecting the same item over and over and over again. 首先,从技术上讲,第一个选项是O(infinity),因为有可能一遍又一遍地随机选择同一项目。 If you want to speak of average cases, it becomes a valid option to consider. 如果您想谈一谈一般情况,那么它就成为一个有效的选择。

The first option is best when the number of items you want is a small percentage of the total size of the collection. 当您想要的项目数仅占集合总大小的一小部分时,第一个选项是最佳选择。 If you only want to grab say 1% of the collection's items then the odds of randomly choosing already chosen items is very, very small. 如果您只想获取该系列商品的1%,那么随机选择已选商品的几率非常小。

The second option, shuffling, on the other hand, is better if you want a large percentage of the items in the collection, because you do the same amount of work regardless of whether you want 1 item or all of them. 另一方面,如果您要在集合中占很大比例的项目,则改组是更好的选择,因为您要做的是相同数量的工作,而不管是要一个项目还是全部项目。 If you only want 1% of the items in the collection then you end up wasting a whole bunch of effort shuffling data that you just don't care about at all. 如果只需要集合中1%的项目,那么最终将浪费大量您根本不在乎的工作量。

Now, what we'd really want to do is randomly shuffle the first N items of the collection, but without shuffling all of the items that are left over. 现在,我们真正想要做的是随机地重新整理集合的前N个项目,但不重新整理所有剩余的项目。

Interestingly enough, this is actually very easy to do. 有趣的是,这实际上很容易做到。 A much more preferable method of shuffling a list is to count down from the highest index to the lowest, pick an item below the current index, and swap it with the current index. 改组列表的一种更可取的方法是从最高索引倒数到最低索引,选择当前索引以下的项目,然后将其与当前索引交换。 This doesn't introduce a bias, unlike sorting, it's O(n) unlike sorting which is O(n*log(n)), and better still, it's super easy to stop part way . 与排序不同,这不会引入偏差,与排序不同的是O(n),它不同于O(n * log(n)),而且更好的是,它很容易停下来 So if we implement this shuffling algorithm: 因此,如果我们实现这种改组算法:

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

We can now write out your solution as: 现在,我们可以将您的解决方案写为:

var selectedHorses = unasignedHorses.Shuffle(rand).Take(numberHorses);
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);

Like I said in the comments though, if your way works now and it makes sense to you, then why change it? 就像我在评论中说的那样,如果您的方式现在可以工作并且对您有意义,那么为什么要更改它? I haven't tried this code but I would think something like this would accomplish what you're looking for. 我没有尝试过这段代码,但是我认为这样的事情可以满足您的需求。 It may seem overly complex but that's how my solutions seems to start and then I end up streamlining them... 它似乎过于复杂,但这就是我的解决方案开始的方式,然后我最终简化了它们。

So you want to pick random object from list 所以你想从列表中选择随机对象

I guess it can be something done like: 我想这可以做到:

int r = rnd.Next(numberHorses.Count);
Horse  selectedHorse  = unnasignedHorses[r];

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM