Как мне написать это на Ruby / Python? Или вы можете перевести мой LINQ на Ruby / Python?

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

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

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

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

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

Именно поэтому мы ясно понимаем это: хотя Python имеет некоторые функциональные конструкции, такие как понимание списков, на самом деле это не функциональный язык, и это не та проблема, которую вы легко могли бы решить в истинном функциональном стиле в Python.

Thomas Wouters 23.09.2008 20:22

Я не понимаю требований. Нужно ли взять N значений и найти отдельные значения в этом наборе? Или нужно найти набор некоторого размера, который имеет N различных значений?

S.Lott 23.09.2008 20:27

Если вы возьмете (5), а затем разделите ... вы можете получить 1 число.

Amy B 23.09.2008 20:40

@ Дэвид: Да, я только что изменил их порядок. Спасибо!

Esteban Araya 23.09.2008 20:42

Готов поспорить, это подразумевает, что LINQ настолько явно превосходит, что никто никогда не сможет создать Ruby или Python, которые соответствуют вашим высоким стандартам «элегантности». Просто догадываюсь. Вопрос хромой, а не хромой который.

S.Lott 23.09.2008 20:46

Я действительно не имел в виду этого - я только вчера начал изучать Ruby и действительно понятия не имел, как это сделать. Мне очень жаль, если я наткнулся на это.

Esteban Araya 23.09.2008 20:57
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
8
6
877
14
Перейти к ответу Данный вопрос помечен как решенный

Ответы 14

Python с числовым Python:

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

Вуаля! Конечно, вы могли бы сделать что-то подобное в стиле функционального программирования, но ... почему?

Потому что это не использует итераторы и сохраняет все целые числа в памяти.

e-satis 23.09.2008 20:43

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

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

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

xrange () фактически не использует генератор. это поддельный список. Генераторы не являются последовательностями и не могут быть проиндексированы, поэтому random.sample () потерпит неудачу, если будет таковой.

Thomas Wouters 23.09.2008 20:21

Почему образцы должны быть уникальными? Кажется, не существует какого-либо фильтра, обеспечивающего уникальность.

S.Lott 23.09.2008 20:26

Функция random.sample () делает это сама. «Вернуть список уникальных элементов длиной k, выбранных из последовательности популяции».

Jeremy 23.09.2008 20:33

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

Вот решение для этого:

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

Но, возможно, вы действительно ищете 5 различных случайных чисел от 0 до 100. В этом случае:

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

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

Теперь, это может нарушить ваше чувство «не слишком много петель», но, по-видимому, Take и Distinct просто скрывают петлю от вас. Было бы достаточно просто добавить методы в Enumerable, чтобы скрыть цикл while.

Верно: я понимаю, что Take & Distinct, вероятно, крутятся за кадром. Я имел в виду отсутствие цикла, который вам нужно было бы написать ... Тем не менее, мне нравятся ваши вторые решения. Спасибо!

Esteban Araya 23.09.2008 20:45

(rand * max).to_i должен быть записан как rand max.

user102008 17.03.2011 11:30

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

s = set()
while len(s) <= N: s.update((random.random(),))
Ответ принят как подходящий

В Ruby:

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

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

Обновлено:

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

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

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

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

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

Да, меня это тоже волновало. Однако мне пока не удалось создать массив с менее чем 5 элементами. Однако это не значит, что это могло произойти. В худшем случае я мог бы вызвать Distinct () раньше Take (), верно?

Esteban Araya 23.09.2008 20:37

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]

Что ж, сначала вы переписываете LINQ на Python. Тогда ваше решение однострочное :)

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

Если вы поместите все вышеперечисленные простые методы в модуль под названием LINQ.py, вы сможете произвести впечатление на своих друзей.

(Отказ от ответственности: конечно, это не фактически, переписывающий LINQ в Python. Люди ошибочно полагают, что LINQ - это просто набор тривиальных методов расширения и некоторый новый синтаксис. Однако действительно продвинутой частью LINQ является автоматическая генерация SQL, так что когда вы запрашиваете базу данных, это база данных, которая реализует Distinct (), а не на стороне клиента.)

Хороший. Небольшой комментарий: вы должны использовать set () вместо хеша в Distince, а ToArray может использовать list ().

olt 24.09.2008 00:46

Обновлено: Хорошо, просто для удовольствия, более короткий и быстрый (и все еще с использованием итераторов).

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]

Если вы удалили дубликат, не получите ли вы меньше значений, чем хотелось бы?

Jeremy 23.09.2008 20:40

Да, но он сделал то же самое в своем вопросе, так что это точный перевод. Вот что требуется: перевод.

e-satis 23.09.2008 20:42

Он этого не сделал - .Take (5) происходит после вызова .Distinct, поэтому будет отрисовываться 5 элементов из уже унифицированной последовательности.

Brian 23.09.2008 23:40

Ничего страшного - просто прочтите комментарий к вопросу, он исправил порядок .Distinct / .Take с момента публикации

Brian 24.09.2008 00:04

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

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

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

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

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

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

from numpy import random,unique

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

randomGenerator = GetRandomNumbers()

myRandomNumbers = randomGenerator.next()

Вот еще одна версия 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

В Ruby 1.9:

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

Другие вопросы по теме