Para hacer un método que repite la fuente una sola vez, y no tiene que asignar memoria para almacenarlo temporalmente, cuente cuántos elementos ha iterado y determine la probabilidad de que el elemento actual sea el resultado:
public T RandomChoice<T> (IEnumerable<T> source) {
Random rnd = new Random();
T result = default(T);
int cnt = 0;
foreach (T item in source) {
cnt++;
if (rnd.Next(cnt) == 0) {
result = item;
}
}
return result;
}
Cuando usted está en el primer elemento, la probabilidad es 1/1 que se debe utilizar (ya que es el único elemento que haya visto hasta aquí). Cuando se encuentra en el segundo elemento, la probabilidad es 1/2 de que deba reemplazar el primer elemento, y así sucesivamente.
Esto, naturalmente, utilizar un poco más de la CPU, ya que crea un número aleatorio por artículo, no sólo un único número al azar para seleccionar un elemento, como dasblinkenlight señaló. Puede comprobar si la fuente implementa IList<T>
, como sugiere Dan Tao, y el uso de una aplicación que utiliza las capacidades para obtener la longitud de los elementos de la colección y de acceso por el índice:
public T RandomChoice<T> (IEnumerable<T> source) {
IList<T> list = source as IList<T>;
if (list != null) {
// use list.Count and list[] to pick an item by random
} else {
// use implementation above
}
}
Nota: Usted debe considerar el envío de la Random
instancia en el método. De lo contrario, obtendrá la misma semilla al azar si llama al método dos veces demasiado cerca en el tiempo, ya que la semilla se crea a partir de la hora actual.
El resultado de una prueba de funcionamiento, recogiendo un número de una matriz que contiene 0 - 9, 1000000 veces, para mostrar que la distribución de los números elegidos no está sesgada:
0: 100278
1: 99519
2: 99994
3: 100327
4: 99571
5: 99731
6: 100031
7: 100429
8: 99482
9: 100638
¿Estás diciendo que quieres una función que te devuelva * exactamente lo que hace Python *? O quieres una función con * el mismo contrato *? Es decir, ¿sería feliz si la función .NET devolviera diferentes elementos de lo que Python haría? – AakashM
Solo para comentar sobre las respuestas proporcionadas, @MattHickford, tal vez deberías considerar, además de un 'IEnumerable' incluir una sobrecarga' IList' (o hacer una comprobación en el 'IEnumerable' si es un' IList') para que puedas evite tener que enumerar y crear una colección copiada. EDITAR: También puede agregar una sobrecarga 'params' para sacar una lista hecha en tiempo de compilación:' RandomChoice ("apple", "pear", "orange") ' –
AakashM, solicito un análogo .NET del Python función. ¿Qué es un contrato? –