最佳LINQ查询来获得一个随机子集 - 洗牌
-
22-07-2019 - |
题
请建议从具有“N”项目的集合获得数“N”的随机洗牌集合的最简单的方法。其中,n <= N
解决方案
另一种选择是使用排序依据和排序上的GUID值,这可以这样做使用:
var result = sequence.OrderBy(elem => Guid.NewGuid());
我做了一些经验测试说服自己的是,上述实际产生的随机分布(其被用来做)。你可以看到我在技术结果重新排序随机数组。
其他提示
继mquander的回答和丹查德的评论,下面是执行的费雪耶茨-Durstenfeld洗牌:
// take n random items from yourCollection
var randomItems = yourCollection.Shuffle().Take(n);
// ...
public static class EnumerableExtensions
{
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source)
{
return source.Shuffle(new Random());
}
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Random rng)
{
if (source == null) throw new ArgumentNullException("source");
if (rng == null) throw new ArgumentNullException("rng");
return source.ShuffleIterator(rng);
}
private static IEnumerable<T> ShuffleIterator<T>(
this IEnumerable<T> source, Random rng)
{
var buffer = source.ToList();
for (int i = 0; i < buffer.Count; i++)
{
int j = rng.Next(i, buffer.Count);
yield return buffer[j];
buffer[j] = buffer[i];
}
}
}
这与“随机偏差”的一些问题,我相信这不是最优的,这是另一种可能性:
var r = new Random();
l.OrderBy(x => r.NextDouble()).Take(n);
洗牌中收集到一个随机的顺序并采取第一n
物品从结果。
一个位少随机的,但有效的:
var rnd = new Random();
var toSkip = list.Count()-n;
if (toSkip > 0)
toSkip = rnd.Next(toSkip);
else
toSkip=0;
var randomlySelectedSequence = list.Skip(toSkip).Take(n);
我写这将覆盖方法:
public static IEnumerable<T> Randomize<T>(this IEnumerable<T> items) where T : class
{
int max = items.Count();
var secuencia = Enumerable.Range(1, max).OrderBy(n => n * n * (new Random()).Next());
return ListOrder<T>(items, secuencia.ToArray());
}
private static IEnumerable<T> ListOrder<T>(IEnumerable<T> items, int[] secuencia) where T : class
{
List<T> newList = new List<T>();
int count = 0;
foreach (var seed in count > 0 ? secuencia.Skip(1) : secuencia.Skip(0))
{
newList.Add(items.ElementAt(seed - 1));
count++;
}
return newList.AsEnumerable<T>();
}
然后,我有源列表(所有项目)
var listSource = p.Session.QueryOver<Listado>(() => pl)
.Where(...);
最后,我称之为“随机化”,我得到物品的随机子集,在我的情况下,5个项目:
var SubCollection = Randomize(listSource.List()).Take(5).ToList();
抱歉丑陋的代码:-),但
var result =yourCollection.OrderBy(p => (p.GetHashCode().ToString() + Guid.NewGuid().ToString()).GetHashCode()).Take(n);
不隶属于 StackOverflow