从List<>?获取单个随机元素的最佳方法是什么?

时间:2014-01-08 16:14:58

标签: .net linq

我需要从列表中获取一个随机元素(这不是列表中的两个值)。以下工作正常:

Company dest = companies
    .Where(cpy => cpy != src && cpy != plyr.PowerUpInAction.Passenger.Destination)
    .OrderBy(pu => rand.Next())
    .ToList()[0];

有更好(即更有效)的方法吗?转换为列表会让我感到额外的工作。

谢谢 - 戴夫

4 个答案:

答案 0 :(得分:3)

您可以.First()代替.ToList()[0]

答案 1 :(得分:1)

接受的答案非常好,但我会使用.FirstOrDefault()代替First()

原因是.First()如果没有找到行,则抛出异常(ArgumentNullException)。这个 意味着你的代码将被停止。你必须添加一个额外的try-catch来处理这个问题。

同一场景中的

.FirstOrDefault()将返回一个null对象(在您的情况下是一个空的Company对象),它根本不会造成任何损坏。您不必添加任何try-catch,也不必在代码中添加null验证。

如果您的公司桌子出于某种原因需要为空,请保存以添加更多代码和未来损坏。这是维护的观点。

答案 2 :(得分:0)

重试,直到找到可接受的元素。这可能是因为只有两个项目被过滤掉了。在最好(可能)的情况下,我们只需一次尝试即可完成。那是O(1)

int retryCount = 0;
while (retryCount < 5) {
 var index = GetRandomIndex(list.Count);
 if (list[index].IsNotFilteredOut)
  return list[index];
 else
  retryCount++;
}

//the fast, probabilistic algorithm has failed. fallback:
return companies.Where(cpy => cpy != src && cpy != plyr.PowerUpInAction.Passenger.Destination).OrderBy(pu => rand.Next()).ToList()[0];

如果我们经常旋转,我们会回到安全算法。

答案 3 :(得分:0)

另一种可能性:

var items = companies.Where( cpy => cpy != src && cpy != plyr.PowerUpInAction.Passenger.Destination );
Company dest = items.First();
int min = int.MaxValue;
foreach( var company in items )
{
    int r = rand.Next();
    if( r < min )
    {
        min = r;
        dest = company;
    }
}

这可以避免对整个列表进行排序以及构建新列表。它仍然是列表大小的线性(因为我们必须评估哪些元素是有效的)。