Comment puis-je écrire cela en Ruby / Python? Ou pouvez-vous traduire mon LINQ en Ruby / Python?

StackOverflow https://stackoverflow.com/questions/122033

Question

Hier, j'ai demandé à cette question et je n'ai jamais vraiment eu de réponse qui me satisfasse vraiment. Je voudrais vraiment savoir comment générer une liste de N nombres aléatoires uniques en utilisant un langage fonctionnel tel que Ruby sans être extrêmement stylé.

Comme je n'ai rien vu qui me plaise vraiment, j'ai écrit la solution que je cherchais dans 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);
            }
        }

Pouvez-vous traduire mon LINQ en Ruby? Python? Un autre langage de programmation fonctionnel?

Remarque: Essayez de ne pas utiliser trop de boucles et de conditions - sinon la solution est triviale. De plus, je préférerais voir une solution dans laquelle il n'est pas nécessaire de générer un tableau beaucoup plus grand que N, vous pouvez donc simplement supprimer les doublons et le réduire à N.

Je sais que je suis difficile, mais j'aimerais vraiment voir des solutions élégantes à ce problème. Merci!

Modifier:
Pourquoi tous les votes négatifs?

À l'origine, mon exemple de code comportait Distinct () après Take (), ce qui, comme beaucoup l'ont souligné, pourrait me laisser une liste vide. J'ai changé l'ordre dans lequel ces méthodes sont appelées pour refléter ce que je voulais dire en premier lieu.

Excuses:
On m'a dit que ce message était plutôt snob. Je n'essayais pas de laisser entendre que LINQ était meilleur que Ruby / Python; ou que ma solution est bien meilleure que celle des autres. Mon intention est juste d'apprendre à faire cela (avec certaines contraintes) en Ruby. Je suis désolé si je suis tombé sur un imbécile.

Était-ce utile?

La solution

En Ruby:

a = (0..100).entries.sort_by {rand}.slice! 0, 5

Mettre à jour : voici une manière légèrement différente:     a = (0 ... 100) .entries.sort_by {rand} [0 ... 5]

EDIT:

et dans Ruby 1.9, vous pouvez le faire:

Array(0..100).sample(5) 

Autres conseils

>>> import random
>>> print random.sample(xrange(100), 5)
[61, 54, 91, 72, 85]

Ceci devrait générer 5 valeurs uniques dans la plage 0 - 99 . L'objet xrange génère les valeurs demandées afin qu'aucune mémoire ne soit utilisée pour les valeurs non échantillonnées.

Hmm ... que diriez-vous de (Python):

s = set()
while len(s) <= N: s.update((random.random(),))

Je vais renoncer aux solutions les plus simples en utilisant le module 'aléatoire' car je suppose que ce n'est pas vraiment ce que vous recherchez. Voici ce que je pense que vous recherchez 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
... 
>>>

Pour vous montrer comment cela fonctionne:

>>> list(getUniqueRandomNumbers(10, 100))
[81, 57, 98, 47, 93, 31, 29, 24, 97, 10]

Voici une autre solution Ruby:

a = (1..5).collect { rand(100) }
a & a

Je pense qu'avec votre déclaration LINQ, Distinct supprimera les doublons après que 5 aient déjà été capturés, vous n'êtes donc pas assuré de récupérer 5. Quelqu'un peut me corriger si je me trompe, cependant.

EDIT: Ok, juste pour le plaisir, un fichier plus court et plus rapide (qui utilise toujours des itérateurs).

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]

Oui, je sais, les one-liners devraient être laissés aux amoureux de Perl, mais je pense que celui-ci est assez puissant, n'est-ce pas?

Ancien message ici:

Mon dieu, comme c'est compliqué tout ça! Soyons pythoniques:

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

Profitez

EDIT: Comme les commentateurs l'ont remarqué, il s'agit d'une traduction exacte du code de la question.

Pour éviter le problème que nous avons rencontré en supprimant les doublons après avoir généré la liste, ce qui donne trop peu de données, vous pouvez choisir un autre moyen:

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]

En Ruby 1.9:

Array(0..100).sample(5)

Python avec Python numérique:

from numpy import *
a = random.random_integers(0, 100, 5)
b = unique(a)

Voil & # 224 ;! Bien sûr, vous pourriez faire quelque chose de similaire dans un style de programmation fonctionnel, mais ... pourquoi?

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]

Eh bien, vous devez d’abord réécrire LINQ en Python. Alors votre solution est un one-liner:)

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 vous mettez toutes les méthodes simples ci-dessus dans un module appelé LINQ.py, vous pourrez impressionner vos amis.

(Avertissement: bien sûr, il ne s'agit pas de réécrire LINQ en Python. Les gens ont la fausse idée que LINQ n'est qu'un tas de méthodes d'extension triviales et une nouvelle syntaxe. La partie vraiment avancée de LINQ Cependant, la génération SQL automatique est telle que lorsque vous interrogez une base de données, c’est la base de données qui implémente Distinct () plutôt que le côté client.)

Voici une translittération de votre solution vers Python.

Tout d'abord, un générateur qui crée des nombres aléatoires. Ce n'est pas très Pythonic, mais c'est un bon accord avec votre exemple de code.

>>> import random
>>> def getRandomNumbers( max ):
...     while True:
...             yield random.randrange(0,max)

Voici une boucle client qui collecte un ensemble de 5 valeurs distinctes. Encore une fois, ce n’est pas l’implémentation la plus pythonique.

>>> distinctSet= set()
>>> for r in getRandomNumbers( 100 ):
...     distinctSet.add( r )
...     if len(distinctSet) == 5: 
...             break
... 
>>> distinctSet
set([81, 66, 28, 53, 46])

La raison pour laquelle vous souhaitez utiliser un générateur pour des nombres aléatoires n’est pas claire. C’est l’une des rares choses qui est si simple qu’un générateur ne le simplifie pas.

Une version plus Pythonic pourrait ressembler à:

distinctSet= set()
while len(distinctSet) != 5:
    distinctSet.add( random.randrange(0,100) )

Si les exigences sont de générer 5 valeurs et de les distinguer des 5, quelque chose comme

distinctSet= set( [random.randrange(0,100) for i in range(5) ] )

Peut-être que cela conviendra à vos besoins et aura un aspect un peu plus linéaire:

from numpy import random,unique

def GetRandomNumbers(total=5):
    while True:
        yield unique(random.random(total*2))[:total]

randomGenerator = GetRandomNumbers()

myRandomNumbers = randomGenerator.next()

Voici une autre version de Python, plus proche de la structure de votre code C #. Il n'y a pas de fonction intégrée pour donner des résultats distincts, alors j'ai ajouté une fonction pour le faire.

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

Je ne peux pas vraiment lire votre LINQ, mais je pense que vous essayez d’obtenir 5 nombres aléatoires allant jusqu’à 100, puis de supprimer les doublons.

Voici une solution pour cela:

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

Mais vous recherchez peut-être 5 nombres aléatoires distincts compris entre 0 et 100. Dans quel cas:

def random(max)
    (rand * max).to_i
end

a = []
while( a.size < 5)
    a << random( 100)
    a = a & a
end

Maintenant, celui-ci pourrait violer votre sens du "pas trop de boucles". mais vraisemblablement, Take et Distinct ne font que cacher la boucle. Il serait assez facile d'ajouter simplement des méthodes à Enumerable pour masquer la boucle while.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top