Consulta Optimal LINQ para obtener una subcategoría aleatoria: reproducción aleatoria

Sugiera la forma más fácil de obtener una colección aleatoria aleatoria de count ‘n’ de una colección que tenga ‘N’ elementos. donde n <= N

Otra opción es utilizar OrderBy y ordenar en un valor GUID, que puede hacer usando:

var result = sequence.OrderBy(elem => Guid.NewGuid()); 

Hice algunas pruebas empíricas para convencerme de que lo anterior en realidad genera una distribución aleatoria (lo que parece hacer). Puedes ver mis resultados en Técnicas para reordenar aleatoriamente una matriz .

Además de la respuesta de mquander y el comentario de Dan Blanchard, aquí hay un método de extensión LINQ-friendly que realiza un barajado de Fisher-Yates-Durstenfeld :

 // take n random items from yourCollection var randomItems = yourCollection.Shuffle().Take(n); // ... public static class EnumerableExtensions { public static IEnumerable Shuffle(this IEnumerable source) { return source.Shuffle(new Random()); } public static IEnumerable Shuffle(this IEnumerable source, Random rng) { if (source == null) throw new ArgumentNullException("source"); if (rng == null) throw new ArgumentNullException("rng"); return source.ShuffleIterator(rng); } private static IEnumerable ShuffleIterator( this IEnumerable 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]; } } } 

Esto tiene algunos problemas con “sesgo aleatorio” y estoy seguro de que no es óptimo, esta es otra posibilidad:

 var r = new Random(); l.OrderBy(x => r.NextDouble()).Take(n); 

Mezcle la colección en un orden aleatorio y tome los primeros n elementos del resultado.

Un poco menos aleatorio, pero eficiente:

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

Escribo este método de anulación:

 public static IEnumerable Randomize(this IEnumerable items) where T : class { int max = items.Count(); var secuencia = Enumerable.Range(1, max).OrderBy(n => n * n * (new Random()).Next()); return ListOrder(items, secuencia.ToArray()); } private static IEnumerable ListOrder(IEnumerable items, int[] secuencia) where T : class { List newList = new List(); 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(); } 

Entonces, tengo mi lista de fonts (todos los artículos)

 var listSource = p.Session.QueryOver(() => pl) .Where(...); 

Finalmente, llamo “aleatorizar” y obtengo una subcolección aleatoria de ítems, en mi caso, 5 ítems:

 var SubCollection = Randomize(listSource.List()).Take(5).ToList(); 

Lo siento por el código feo :-), pero

var result =yourCollection.OrderBy(p => (p.GetHashCode().ToString() + Guid.NewGuid().ToString()).GetHashCode()).Take(n);
var result =yourCollection.OrderBy(p => (p.GetHashCode().ToString() + Guid.NewGuid().ToString()).GetHashCode()).Take(n);