如何从数组中随机选择?

645

我想知道是否有更加简洁的方法来实现这个功能。基本上,我想从一个长度可变的数组中随机选择一个元素。通常,我会像这样做:

myArray = ["stuff", "widget", "ruby", "goodies", "java", "emerald", "etc" ]
item = myArray[rand(myarray.length)]

有没有更易读/更简单的方法替换第二行?还是这是最好的方法。我想你可以做myArray.shuffle.first,但是我几分钟前只看到了#shuffle,我还没有真正使用它。


13
以下是一个很好的回答,但关于洗牌还有一般性的观点。我想完整地洗牌比仅获取随机数要更加耗费资源,因此这不是一个明智的方向。 - Derek Organ
7个回答

1266

只需使用 Array#sample

[:foo, :bar].sample # => :foo, or :bar :-)

它在Ruby 1.9.1+中可用。如果您还想将其与早期版本的Ruby一起使用,可以require "backports/1.9.1/array/sample"

请注意,在Ruby 1.8.7中,它存在一个不幸的名字choice; 它在后来的版本中更名了,因此您不应该使用那个名字。

虽然在这种情况下不是很有用,但sample接受数字参数,以便您想要获取一些不同的样本。


1
我应该知道你会为我提供完美的答案(因为我在这里浏览的大多数Ruby问题都有你的输入)。我很高兴你指出了版本问题;我正在使用1.9.2。 apidock(mladen的评论)没有示例; ruby-doc也没有。在你的意见中,最好的Ruby参考资料是什么,更新到1.9? - Paul Hoffer
1
谢谢 :-) 是的,这是被鼓励的(请参见http://meta.stackexchange.com/questions/19448/etiquette-for-selecting-answers) - Marc-André Lafortune
3
@Andrew:是的,我编辑了我的回答,因为1.8.8不会出现。它应该仍然在1.8-head中,但是那个分支已经死了 :-( - Marc-André Lafortune
方便的是,您还可以在ActiveRecord :: Relation上使用sample; 例如,@joe.pencils.sample将从Joe的铅笔集合中随机选择一种书写工具(假设这里是正常的Rails操作)。 - Purplejacket
1
@Purplejacket:是的,但这可能不是最好的方法。ActiveRecord::Relation会将调用委托给一个数组,因此它将加载所有记录,然后随机选择一个。 - Marc-André Lafortune
显示剩余5条评论

103

myArray.sample(x)也可以帮助您从数组中获取x个随机元素。


10
值得注意的是,my_array.sample(1) 不等于 my_array.sample。 - Redithion
8
值得注意的是,my_array.sample(1) == [sample] 和 my_array.sample == sample 之间的区别在于前者返回一个包含所选样本的数组,而后者直接返回所选样本。因此在表达意思时需要明确指出你的意图。 - Ekkstein
太好了,这正是我在寻找的。 - alexventuraio

23
myArray.sample

将返回 1 个随机值。

myArray.shuffle.first

还会返回1个随机值。


31
洗牌是多余的。 - superluminary
1
从技术上讲,这种随机方法也是正确的 https://dev59.com/e3VD5IYBdhLWcg3wHnsX#84747 - Filip Bartuzi

17

从数组中随机选择随机数量的项

def random_items(array)
  array.sample(1 + rand(array.count))
end

可能的结果示例:

my_array = ["one", "two", "three"]
my_array.sample(1 + rand(my_array.count))

=> ["two", "three"]
=> ["one", "three", "two"]
=> ["two"]

@fwilson 随机的对象集合,无任何顺序。也适用于测试不同的组合或生成存根数据。 - Mike Rapadas
为什么不扩展Array类?[].total_random会更酷。来吧,这是Ruby。它是面向对象的! - Tim Kretschmer
这将永远不会返回一个空数组。你需要把 1 + 放在另一个地方。 - sawa

5

以下是我对这里发布的一些答案进行基准测试的结果,使用 sample 通常比其他方法更快。

test_arr = ["stuff", "widget", "ruby", "goodies", "java", "emerald" ]

Benchmark.ips do |x|
  x.report("1 - sample") { test_arr.sample }
  x.report("2 - shuffle") { test_arr.shuffle.first }
  x.report("3 - length") { rand(test_arr.length) }
  x.report("4 - rand rand") { test_arr.sample(1 + rand(test_arr.count)) }
  x.report("5 - rand el") { test_arr[rand(test_arr.count)]}
  x.report("6 - switch") { 
    case rand(0..test_arr.length)      
    when 0
      test_arr[0]
    when 1
      test_arr[1]
    when 2
      test_arr[2]
    when 3
      test_arr[3]
    when 4
      test_arr[4]
    when 5
      test_arr[5]
    end 
  }  

  x.compare!

这些测试是在一台MacBook Pro (15英寸, 2018年款)上进行的,配备了2.6 GHz六核Intel Core i7处理器和32 GB 2400 MHz DDR4内存。

Warming up --------------------------------------
          1 - sample   713.455k i/100ms
         2 - shuffle   253.848k i/100ms
          3 - length   489.078k i/100ms
       4 - rand rand   236.396k i/100ms
         5 - rand el   447.244k i/100ms
          6 - switch   419.272k i/100ms
Calculating -------------------------------------
          1 - sample      7.505M (± 3.2%) i/s -     37.813M in   5.044078s
         2 - shuffle      2.661M (± 2.1%) i/s -     13.454M in   5.057659s
          3 - length      5.021M (± 1.6%) i/s -     25.432M in   5.066159s
       4 - rand rand      2.352M (± 2.4%) i/s -     11.820M in   5.029415s
         5 - rand el      4.452M (± 2.2%) i/s -     22.362M in   5.025623s
          6 - switch      4.324M (± 1.1%) i/s -     21.802M in   5.043294s

Comparison:
          1 - sample:  7504636.7 i/s
          3 - length:  5021326.6 i/s - 1.49x  (± 0.00) slower
         5 - rand el:  4452078.6 i/s - 1.69x  (± 0.00) slower
          6 - switch:  4323511.6 i/s - 1.74x  (± 0.00) slower
         2 - shuffle:  2661267.7 i/s - 2.82x  (± 0.00) slower
       4 - rand rand:  2351630.7 i/s - 3.19x  (± 0.00) slower

1
arr = [1,9,5,2,4,9,5,8,7,9,0,8,2,7,5,8,0,2,9]
arr[rand(arr.count)]

这将从数组中返回一个随机元素。
如果您使用下面提到的行
arr[1+rand(arr.count)]

有时会返回0或nil值。

下面提到的行

rand(number)

请始终返回从0到数字-1的值。

如果我们使用

1+rand(number)

那么它可能会返回数字,而arr[number]不包含任何元素。


-8
class String

  def black
    return "\e[30m#{self}\e[0m"
  end

  def red
    return "\e[31m#{self}\e[0m"
  end

  def light_green
    return "\e[32m#{self}\e[0m"
  end

  def purple
    return "\e[35m#{self}\e[0m"
  end

  def blue_dark
    return "\e[34m#{self}\e[0m"
  end

  def blue_light
    return "\e[36m#{self}\e[0m"
  end

  def white
    return "\e[37m#{self}\e[0m"
  end


  def randColor
    array_color = [
      "\e[30m#{self}\e[0m",
      "\e[31m#{self}\e[0m",
      "\e[32m#{self}\e[0m",
      "\e[35m#{self}\e[0m",
      "\e[34m#{self}\e[0m",
      "\e[36m#{self}\e[0m",
      "\e[37m#{self}\e[0m" ]

      return array_color[rand(0..array_color.size)]
  end


end
puts "black".black
puts "red".red
puts "light_green".light_green
puts "purple".purple
puts "dark blue".blue_dark
puts "light blue".blue_light
puts "white".white
puts "random color".randColor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接