Как мне написать это на Ruby / Python? Или вы можете перевести мой LINQ на Ruby / Python? - PullRequest
8 голосов
/ 23 сентября 2008

Вчера я задал этот вопрос и так и не получил ответа, которым был очень доволен. Я действительно хотел бы знать, как создать список из N уникальных случайных чисел, используя функциональный язык, такой как Ruby, без необходимости быть крайне обязательным в стиле.

Поскольку я не видел ничего, что мне действительно нравилось, я написал решение, которое искал в 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);
            }
        }

Можете ли вы перевести мой LINQ на Ruby? Python? Любой другой функциональный язык программирования?

Примечание: Пожалуйста, старайтесь не использовать слишком много циклов и условных выражений - в противном случае решение будет тривиальным. Кроме того, я бы предпочел найти решение, в котором вам не нужно генерировать массив, намного больший, чем N, чтобы вы могли затем просто удалить дубликаты и обрезать его до N.

Я знаю, что я привередлив, но мне бы очень хотелось увидеть некоторые элегантные решения этой проблемы. Спасибо!

Edit:
Почему все отрицательные?

Первоначально мой пример кода имел функцию Distinct () после Take (), которая, как отмечали многие, могла оставить меня с пустым списком. Я изменил порядок, в котором эти методы вызываются, чтобы отразить то, что я имел в виду.

Апология:
Мне сказали, что этот пост показался мне довольно снобистским. Я не пытался сказать, что LINQ лучше Ruby / Python; или что мое решение намного лучше, чем у всех остальных. Я собираюсь научиться делать это (с некоторыми ограничениями) в Ruby. Извините, если я натолкнулся на этого.

Ответы [ 14 ]

13 голосов
/ 23 сентября 2008
>>> import random
>>> print random.sample(xrange(100), 5)
[61, 54, 91, 72, 85]

Это должно дать 5 уникальных значений в диапазоне 0 — 99. Объект xrange генерирует значения по запросу, поэтому память для значений, которые не были выбраны, не используется.

5 голосов
/ 23 сентября 2008

в рубине:

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

Обновление : Вот немного другой способ: a = (0 ... 100) .entries.sort_by {rand} [0 ... 5]

EDIT:

и в Ruby 1.9 вы можете сделать это:

Array(0..100).sample(5) 
3 голосов
/ 23 сентября 2008

Хмм ... Как насчет (Python):

s = set()
while len(s) <= N: s.update((random.random(),))
2 голосов
/ 23 сентября 2008

РЕДАКТИРОВАТЬ: Хорошо, просто для удовольствия, короче и быстрее (и все еще с использованием итераторов).

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]

Да, я знаю, однострочники следует оставить любителям Perl, но я думаю, что этот достаточно мощный, не так ли?

Старое сообщение здесь:

Боже мой, как все это сложно! Давайте будем питонами:

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

Наслаждайтесь

РЕДАКТИРОВАТЬ: Как заметили комментаторы, это точный перевод кода вопроса.

Чтобы избежать проблемы, возникшей при удалении дубликатов после создания списка, что приводит к слишком малому количеству данных, вы можете выбрать другой способ:

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]
2 голосов
/ 23 сентября 2008

Вот еще одно решение Ruby:

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

Я думаю, что с вашим оператором LINQ Distinct удалит дубликаты после того, как 5 уже были взяты, поэтому вы не гарантированно получите 5 обратно. Кто-то может исправить меня, если я ошибаюсь.

2 голосов
/ 23 сентября 2008

Я воздержусь от самых простых решений, использующих модуль 'random', поскольку, как я понимаю, это не совсем то, что вам нужно Вот что я думаю, что вы ищете в 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
... 
>>>

Чтобы показать вам, как это работает:

>>> list(getUniqueRandomNumbers(10, 100))
[81, 57, 98, 47, 93, 31, 29, 24, 97, 10]
1 голос
/ 25 сентября 2010

В Ruby 1.9:

Array(0..100).sample(5)
0 голосов
/ 23 сентября 2008

Вот еще одна версия Python, более точно соответствующая структуре вашего кода C #. Нет встроенной функции для выдачи четких результатов, поэтому я добавил функцию для этого.

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
0 голосов
/ 23 сентября 2008

Может быть, это подойдет вашим потребностям и будет выглядеть более по-английски:

from numpy import random,unique

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

randomGenerator = GetRandomNumbers()

myRandomNumbers = randomGenerator.next()
0 голосов
/ 23 сентября 2008

Вот транслитерация из вашего решения на Python.

Во-первых, генератор, который создает случайные числа. Это не очень Pythonic, но это хорошо соответствует вашему примеру кода.

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

Вот клиентский цикл, который собирает набор из 5 различных значений. Это - опять же - не самая Pythonic реализация.

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

Не ясно, почему вы хотите использовать генератор для случайных чисел - это одна из немногих вещей, которые настолько просты, что генератор не упрощает это.

Более Pythonic версия может быть что-то вроде:

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

Если требуется сгенерировать 5 значений и найти их среди этих 5, то что-то вроде

distinctSet= set( [random.randrange(0,100) for i in range(5) ] )
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...