8

昨日、私はこの質問をしましたが、本当に満足できる答えが得られませんでした. Ruby などの関数型言語を使用して、スタイルが非常に命令的である必要なく、N 個の一意の乱数のリストを生成する方法を本当に知りたいです。

本当に気に入ったものが見つからなかったので、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 に翻訳できますか? パイソン?他の関数型プログラミング言語はありますか?

注:ループや条件を使いすぎないようにしてください。そうしないと、解決策は簡単です。また、N よりもはるかに大きな配列を生成する必要がなく、重複を削除して N に切り詰めることができる解決策を見たいと思います。

私はうるさいことを知っていますが、この問題に対するいくつかのエレガントな解決策を見たいと思っています. ありがとう!

編集:
なぜすべてのマイナス投票なのですか?

もともと私のコード サンプルには、Take() の後に Distinct() があり、多くの人が指摘したように、空のリストが残る可能性がありました。そもそもの意図を反映するために、これらのメソッドが呼び出される順序を変更しました。

お詫び:
この投稿はかなり気取ったものだと言われてしまいました。LINQ が Ruby/Python よりも優れているとほのめかしているわけではありません。または、私の解決策が他の人の解決策よりもはるかに優れていること。私の意図は、Ruby で (特定の制約を使用して) これを行う方法を学ぶことです。ばかみたいに出くわしたらごめんなさい。

4

14 に答える 14

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

これにより、範囲内に 5 つの一意の値が生成されます0 — 99。オブジェクトはxrange要求どおりに値を生成するため、サンプリングされていない値にメモリは使用されません。

于 2008-09-23T16:18:19.447 に答える
5

ルビーの場合:

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) 
于 2008-09-23T16:27:31.920 に答える
3

うーん...どうですか(Python):

s = set()
while len(s) <= N: s.update((random.random(),))
于 2008-09-23T16:24:18.730 に答える
2

別の Ruby ソリューションを次に示します。

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

あなたの LINQ ステートメントでは、Distinct は 5 つが取得された後に重複を削除するため、5 つが返される保証はないと思います。私が間違っていても、誰かが私を正すことができます。

于 2008-09-23T16:28:02.340 に答える
2

編集:わかりました、ただの楽しみのために、短くて速いものです(そしてまだイテレータを使用しています)。

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 愛好家に任せるべきですが、これは非常に強力だと思いますね。

ここに古いメッセージ:

なんと複雑なことでしょう。Pythonic になりましょう:

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]
于 2008-09-23T16:38:45.497 に答える
2

「ランダム」モジュールを使用した最も単純なソリューションは省略します。これは、実際にはあなたが求めているものではないからです。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]
于 2008-09-23T16:17:48.713 に答える
1

Ruby 1.9 では:

Array(0..100).sample(5)
于 2010-09-25T09:17:24.077 に答える
0

これは別の 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
于 2008-09-23T19:33:19.820 に答える
0
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]
于 2008-09-23T16:31:02.240 に答える
0

数値 Python を使用した Python:

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

ほら!確かに、関数型プログラミング スタイルで同様のことを行うことはできますが、なぜでしょうか?

于 2008-09-23T16:13:51.157 に答える
0

まず、Python で LINQ を書き直します。次に、あなたのソリューションはワンライナーです:)

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 というモジュールに入れると、友達に感銘を与えることができます。

(免責事項: もちろん、これは実際に Python で LINQ を書き直しているわけではありません。人々は LINQ が単純な拡張メソッドといくつかの新しい構文の集まりに過ぎないという誤解を持っています。しかし、LINQ の本当に高度な部分は自動 SQL 生成です。データベースにクエリを実行している場合、クライアント側ではなく Distinct() を実装するのはデータベースです)。

于 2008-09-23T16:32:42.470 に答える
0

これは、ソリューションから 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])

乱数にジェネレーターを使用する理由は明確ではありません。これは、ジェネレーターが単純化できないほど単純な数少ないものの 1 つです。

より 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) ] )
于 2008-09-23T16:42:27.577 に答える
0

たぶん、これはあなたのニーズに合っていて、もう少しリンキーに見えるでしょう:

from numpy import random,unique

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

randomGenerator = GetRandomNumbers()

myRandomNumbers = randomGenerator.next()
于 2008-09-23T16:57:09.180 に答える
-1

LINQ を実際に読み取ることはできませんが、100 までの 5 つの乱数を取得して重複を削除しようとしていると思います。

そのための解決策は次のとおりです。

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

しかし、実際には 0 から 100 までの 5 つの異なる乱数を探しているのかもしれません。その場合:

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

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

さて、これは「ループが多すぎない」というあなたの感覚に反するかもしれませんが、おそらく、Take と Distinct はループを隠しているだけでしょう。Enumerable にメソッドを追加して while ループを隠すのは簡単です。

于 2008-09-23T16:23:30.090 に答える