如何生成Ruby中n独特的随机数的列表?(How do I generate a list of n

2019-06-17 17:04发布

这是我到目前为止有:

myArray.map!{ rand(max) }

但很明显的,有时在列表中的号码是不是唯一的。 我怎样才能让,而无需创建一个更大的列表,从中我那么随便挑n个独特的数字肯定我的列表中只有唯一的数字?

编辑:
我很想看到这个做W / O循环 - 如果可能的话。

Answer 1:

它使用设置:

require 'set'

def rand_n(n, max)
    randoms = Set.new
    loop do
        randoms << rand(max)
        return randoms.to_a if randoms.size >= n
    end
end


Answer 2:

(0..50).to_a.sort{ rand() - 0.5 }[0..x] 

(0..50).to_a可以与任何阵列来代替。 0是“MINVALUE”,50为“最大值” X是“有多少价值,我想出去”

当然,其不可能被允许X为比最大最小更大:)

在如何工作的扩展

(0..5).to_a  ==> [0,1,2,3,4,5]
[0,1,2,3,4,5].sort{ -1 }  ==>  [0, 1, 2, 4, 3, 5]  # constant
[0,1,2,3,4,5].sort{  1 }  ==>  [5, 3, 0, 4, 2, 1]  # constant
[0,1,2,3,4,5].sort{ rand() - 0.5 }   ==>  [1, 5, 0, 3, 4, 2 ]  # random
[1, 5, 0, 3, 4, 2 ][ 0..2 ]   ==>  [1, 5, 0 ]

脚注:

值得一提的是,在当时这个问题最初回答,2008年9月,该Array#shuffle要么不提供或不已经知道我,因此近似Array#sort

还有的修改建议接二连三这个结果。

所以:

.sort{ rand() - 0.5 }

可以更好的和更短的使用现代Ruby实现表达

.shuffle

另外,

[0..x]

可以更明显地写有Array#take如下:

.take(x)

因此,生产上的现代红宝石随机数序列的最简单的方法是:

(0..50).to_a.shuffle.take(x)


Answer 3:

只给你关于速度的想法,我跑的这四个版本:

  1. 用集合,像瑞安的建议。
  2. 使用非必要稍大的数组,然后做的uniq! 在末尾。
  3. 使用散,像凯尔建议。
  4. 创建所需大小的数组,然后分拣它随机,像肯特的建议(但没有多余的“ - 0.5”,它什么都不做)。

他们都很快在小尺度,所以我让他们每个创建百万号码列表。 这里有时间,以秒为:

  1. 组数:628
  2. 阵列+ uniq的:629
  3. 哈希:645
  4. 固定阵列+排序:8

不,那最后一个是不是一个错字。 所以,如果你在乎速度,这是确定的数字是从0到什么,然后我确切的代码是整数:

a = (0...1000000).sort_by{rand}


Answer 4:

红宝石1.9提供,它返回一个元素,或从数组随机选择的元件阵列#样品的方法。 #sample的结果将不包括两次相同的数组元素。

(1..999).to_a.sample 5 # => [389, 30, 326, 946, 746]

当相比于to_a.sort_by方法中, sample的方法似乎是显著更快。 在一个简单的场景我比较sort_bysample ,并得到下面的结果。

require 'benchmark'
range = 0...1000000
how_many = 5

Benchmark.realtime do
  range.to_a.sample(how_many)
end
=> 0.081083

Benchmark.realtime do
  (range).sort_by{rand}[0...how_many]
end
=> 2.907445


Answer 5:

是的,这是可以做到这一点没有一个循环,并没有保留这些号码已被选定轨道。 这就是所谓的线性反馈移位寄存器: 有没有重复创建随机数序列



Answer 6:

如何在这个戏? 独特的随机数,而无需使用设置或哈希。

x = 0
(1..100).map{|iter| x += rand(100)}.shuffle


Answer 7:

你可以使用哈希来跟踪到目前为止你已经使用的随机数:

seen = {}
max = 100
(1..10).map { |n|
  x = rand(max)
  while (seen[x]) 
    x = rand(max)
  end
  x
}


Answer 8:

而不是项目添加到列表/数组,将它们添加到组。



Answer 9:

如果有可能的随机数(即1〜100)的有限列表,然后肯特的解决方案是好的。

否则,有没有另做它没有循环的好方法。 问题是你必须做的一环,如果你得到一个副本。 我的解决办法应该是高效和循环不应该比你的数组的大小太大以上(也就是说,如果你想20张不同的随机数,它可能平均需要25次迭代。)虽然迭代的次数变得更糟了更多的数字你需要和较小的最大值是。 下面是修改了我上面的代码显示有多少次迭代都需要给定输入:

require 'set'

def rand_n(n, max)
    randoms = Set.new
    i = 0
    loop do
        randoms << rand(max)
        break if randoms.size > n
        i += 1
    end
    puts "Took #{i} iterations for #{n} random numbers to a max of #{max}"
    return randoms.to_a
end

我可以写这样的代码,如果你想看起来更像Array.map :)



Answer 10:

基于以上肯特弗雷德里克的解决方案,这就是我最终使用:

def n_unique_rand(number_to_generate, rand_upper_limit)
  return (0..rand_upper_limit - 1).sort_by{rand}[0..number_to_generate - 1]
end

感谢肯特。



Answer 11:

用这种方法没有循环

Array.new(size) { rand(max) }

require 'benchmark'
max = 1000000
size = 5
Benchmark.realtime do
  Array.new(size) { rand(max) }
end

=> 1.9114e-05 


Answer 12:

这里是一个解决方案:

假设你希望这些随机数是介于r_minr_max 。 对于在列表中的每个元素,生成一个随机数r使list[i]=list[i-1]+r 。 这将使你的随机数这是单调递增,保证独特性规定

  • r+list[i-1]不超过流
  • r > 0

对于第一个元素,你可以使用r_min ,而不是list[i-1] 一旦你完成,你可以这样的元素不是那么明显,为了改组列表。

用这种方法唯一的问题是,当你去r_max ,仍然有更多的元素来产生。 在这种情况下,您可以重置r_minr_max你已经计算出两个相邻的元素,简单地重复这个过程。 这有效地运行在那里有没有已经使用的号码的间隔相同的算法。 您可以继续这样做,直到你有填充列表。



Answer 13:

至于它是很好预先知道的最大信号值,你可以这样说:

class NoLoopRand
  def initialize(max)
    @deck = (0..max).to_a
  end

  def getrnd
    return @deck.delete_at(rand(@deck.length - 1))
  end
end

你可以得到这样的随机数据:

aRndNum = NoLoopRand.new(10)
puts aRndNum.getrnd

你会获得nil当所有的值将从甲板exausted。



Answer 14:

方法1

使用肯特的方法,它是能够产生任意长度保持所有值在有限范围内的数组:

# Generates a random array of length n.
#
# @param n     length of the desired array
# @param lower minimum number in the array
# @param upper maximum number in the array
def ary_rand(n, lower, upper)
    values_set = (lower..upper).to_a
    repetition = n/(upper-lower+1) + 1
    (values_set*repetition).sample n
end

方法2

另外,可能更有效 ,方法同样从肯特郡的修改另一个答案 :

def ary_rand2(n, lower, upper)
    v = (lower..upper).to_a
    (0...n).map{ v[rand(v.length)] }
end

产量

puts (ary_rand 5, 0, 9).to_s # [0, 8, 2, 5, 6] expected
puts (ary_rand 5, 0, 9).to_s # [7, 8, 2, 4, 3] different result for same params
puts (ary_rand 5, 0, 1).to_s # [0, 0, 1, 0, 1] repeated values from limited range
puts (ary_rand 5, 9, 0).to_s # []              no such range :)


文章来源: How do I generate a list of n unique random numbers in Ruby?
标签: ruby random