무작위 하위 컬렉션을 얻기위한 최적의 LINQ 쿼리 -Shuffle
-
22-07-2019 - |
문제
'n'항목이있는 컬렉션에서 임의의 셔플 링 된 Count 'n'을 얻는 가장 쉬운 방법을 제안하십시오. 여기서 n <= n
해결책
또 다른 옵션은 Orderby를 사용하고 안내 값을 정렬하는 것입니다.
var result = sequence.OrderBy(elem => Guid.NewGuid());
나는 상기가 실제로 무작위 분포를 생성한다는 것을 확신시키기 위해 경험적 테스트를 수행했습니다. 내 결과를 볼 수 있습니다 배열을 무작위로 재정렬하는 기술.
다른 팁
Mquander의 답변과 Dan Blanchard의 의견에 따라 다음은 다음을 수행하는 LINQ 친화적 인 확장 방법이 있습니다. Fisher-Yates-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(...);
마지막으로, 나는 "Randomize"라고 부르고 5 개의 항목에 대한 무작위 항목을 수집합니다.
var SubCollection = Randomize(listSource.List()).Take(5).ToList();
못생긴 코드에 대해 죄송합니다 :-), 그러나
var result =yourCollection.OrderBy(p => (p.GetHashCode().ToString() + Guid.NewGuid().ToString()).GetHashCode()).Take(n);
제휴하지 않습니다 StackOverflow