replit - ¿Cómo escribo esto en Ruby/Python? O bien, ¿puedes traducir mi LINQ a Ruby/Python?
pseudocodigo online (14)
Aquí hay otra solución de Ruby:
a = (1..5).collect { rand(100) }
a & a
Creo que, con su declaración LINQ, Distinct eliminará los duplicados una vez que se hayan tomado 5, por lo que no se garantiza que recuperarán 5. Aunque alguien puede corregirme si me equivoco.
Ayer, hice esta pregunta y nunca obtuve una respuesta con la que estaba realmente feliz. Realmente me gustaría saber cómo generar una lista de N números aleatorios únicos usando un lenguaje funcional como Ruby sin tener que ser extremadamente imperativo en estilo.
Como no vi nada que realmente me gustara, escribí la solución que estaba buscando en LINQ:
static void Main(string[] args)
{
var temp = from q in GetRandomNumbers(100).Distinct().Take(5) select q;
}
private static IEnumerable GetRandomNumbers(int max)
{
Random r = new Random();
while (true)
{
yield return r.Next(max);
}
}
¿Puedes traducir mi LINQ a Ruby? ¿Pitón? ¿Algún otro lenguaje de programación funcional?
Nota: Intente no utilizar demasiados bucles y condicionales; de lo contrario, la solución es trivial. Además, prefiero ver una solución en la que no tenga que generar una matriz mucho más grande que N, por lo que puede eliminar los duplicados y recortarlos en N.
Sé que soy exigente, pero realmente me gustaría ver algunas soluciones elegantes para este problema. ¡Gracias!
Editar:
¿Por qué todos los votos a favor?
Originalmente, mi muestra de código tenía Distinct () después de Take () que, como muchos señalaron, podría dejarme con una lista vacía. He cambiado el orden en que se llaman esos métodos para reflejar lo que quise decir en primer lugar.
Disculpa:
Me han dicho que esta publicación me pareció bastante esnob. No estaba tratando de dar a entender que LINQ es mejor que Ruby / Python; o que mi solución es mucho mejor que la de los demás. Mi intención es solo aprender a hacer esto (con ciertas restricciones) en Ruby. Lo siento si me encontré como un idiota.
Aquí hay otra versión de Python, que se aproxima más a la estructura de su código C #. No hay una función incorporada para dar resultados distintos, así que he agregado una función para hacer esto.
import itertools, random
def distinct(seq):
seen=set()
for item in seq:
if item not in seen:
seen.add(item)
yield item
def getRandomNumbers(max):
while 1:
yield random.randint(0,max)
for item in itertools.islice(distinct(getRandomNumbers(100)), 5):
print item
Aquí hay una transcripción de su solución a Python.
Primero, un generador que crea números aleatorios. Esto no es muy pitónico, pero es una buena coincidencia con su código de muestra.
>>> import random
>>> def getRandomNumbers( max ):
... while True:
... yield random.randrange(0,max)
Aquí hay un bucle de cliente que recopila un conjunto de 5 valores distintos. Esto es, de nuevo, no la implementación más Pythonic.
>>> distinctSet= set()
>>> for r in getRandomNumbers( 100 ):
... distinctSet.add( r )
... if len(distinctSet) == 5:
... break
...
>>> distinctSet
set([81, 66, 28, 53, 46])
No está claro por qué quiere usar un generador para números aleatorios; esa es una de las pocas cosas que es tan simple que un generador no lo simplifica.
Una versión más Pythonic podría ser algo como:
distinctSet= set()
while len(distinctSet) != 5:
distinctSet.add( random.randrange(0,100) )
Si los requisitos son generar 5 valores y encontrar distintos entre esos 5, entonces algo como
distinctSet= set( [random.randrange(0,100) for i in range(5) ] )
Bueno, primero reescribes LINQ en Python. Entonces tu solución es de una sola línea :)
from random import randrange
def Distinct(items):
set = {}
for i in items:
if not set.has_key(i):
yield i
set[i] = 1
def Take(num, items):
for i in items:
if num > 0:
yield i
num = num - 1
else:
break
def ToArray(items):
return [i for i in items]
def GetRandomNumbers(max):
while 1:
yield randrange(max)
print ToArray(Take(5, Distinct(GetRandomNumbers(100))))
Si coloca todos los métodos simples arriba en un módulo llamado LINQ.py, puede impresionar a sus amigos.
(Descargo de responsabilidad: por supuesto, esto no está reescribiendo LINQ en Python. La gente tiene la idea errónea de que LINQ es solo un montón de métodos de extensión triviales y una nueva sintaxis. Sin embargo, la parte realmente avanzada de LINQ es la generación automática de SQL, de modo que cuando está consultando una base de datos, es la base de datos que implementa Distinct () en lugar del lado del cliente).
EDITAR: Ok, solo por diversión, uno más corto y más rápido (y aún usando iteradores).
def getRandomNumbers(max, size) :
pool = set()
return ((lambda x : pool.add(x) or x)(random.randrange(max)) for x in xrange(size) if len(a) < size)
print [x for x in gen(100, 5)]
[0, 10, 19, 51, 18]
Sí, lo sé, a los enamorados se les debe dejar a los amantes, pero creo que este es bastante poderoso ¿no?
Viejo mensaje aquí:
Dios mío, ¡qué complicado es todo eso! Seamos pitónicos:
import random
def getRandomNumber(max, size, min=0) :
# using () and xrange = using iterators
return (random.randrange(min, max) for x in xrange(size))
print set(getRandomNumber(100, 5)) # set() removes duplicates
set([88, 99, 29, 70, 23])
Disfrutar
EDITAR: Como notaron los comentaristas, esta es una traducción exacta del código de la pregunta.
Para evitar el problema que obtuvimos al eliminar los duplicados después de generar la lista, lo que resulta en muy pocos datos, puede elegir otra forma:
def getRandomNumbers(max, size) :
pool = []
while len(pool) < size :
tmp = random.randrange(max)
if tmp not in pool :
yield pool.append(tmp) or tmp
print [x for x in getRandomNumbers(5, 5)]
[2, 1, 0, 3, 4]
Hmm ... ¿Qué tal (Python):
s = set()
while len(s) <= N: s.update((random.random(),))
Python con Numeric Python:
from numpy import *
a = random.random_integers(0, 100, 5)
b = unique(a)
Voilà! Claro que podrías hacer algo similar en un estilo de programación funcional, pero ... ¿por qué?
Realmente no puedo leer su LINQ, pero creo que está tratando de obtener 5 números aleatorios hasta 100 y luego eliminar duplicados.
Aquí hay una solución para eso:
def random(max)
(rand * max).to_i
end
# Get 5 random numbers between 0 and 100
a = (1..5).inject([]){|acc,i| acc << random( 100)}
# Remove Duplicates
a = a & a
Pero quizás estés buscando 5 números aleatorios distintos entre 0 y 100. En cuyo caso:
def random(max)
(rand * max).to_i
end
a = []
while( a.size < 5)
a << random( 100)
a = a & a
end
Ahora, este podría violar tu sensación de "no demasiados bucles", pero presumiblemente Take and Distinct te oculta el bucle. Sería bastante fácil simplemente agregar métodos a Enumerable para ocultar el ciclo while.
Renunciaré a las soluciones más simples usando el módulo ''aleatorio'', ya que considero que eso no es realmente lo que buscas. Esto es lo que creo que estás buscando en Python:
>>> import random
>>>
>>> def getUniqueRandomNumbers(num, highest):
... seen = set()
... while len(seen) < num:
... i = random.randrange(0, highest)
... if i not in seen:
... seen.add(i)
... yield i
...
>>>
Para mostrarte cómo funciona:
>>> list(getUniqueRandomNumbers(10, 100))
[81, 57, 98, 47, 93, 31, 29, 24, 97, 10]
Tal vez esto se adapte a tus necesidades y se vea un poco más complejo:
from numpy import random,unique
def GetRandomNumbers(total=5):
while True:
yield unique(random.random(total*2))[:total]
randomGenerator = GetRandomNumbers()
myRandomNumbers = randomGenerator.next()
import random
def makeRand(n):
rand = random.Random()
while 1:
yield rand.randint(0,n)
yield rand.randint(0,n)
gen = makeRand(100)
terms = [ gen.next() for n in range(5) ]
print "raw list"
print terms
print "de-duped list"
print list(set(terms))
# produces output similar to this
#
# raw list
# [22, 11, 35, 55, 1]
# de-duped list
# [35, 11, 1, 22, 55]
En Ruby 1.9:
Array(0..100).sample(5)
En Ruby:
a = (0..100).entries.sort_by {rand}.slice! 0, 5
Actualización : Aquí hay una manera ligeramente diferente: a = (0 ... 100) .entries.sort_by {rand} [0 ... 5]
EDITAR:
y en Ruby 1.9 puedes hacer esto:
Array(0..100).sample(5)
>>> import random
>>> print random.sample(xrange(100), 5)
[61, 54, 91, 72, 85]
Esto debería producir 5 valores únicos en el rango 0 — 99
. El objeto xrange
genera los valores solicitados, por lo que no se utiliza memoria para los valores que no se muestrean.