仅在Ruby ONCE中从数组中选取随机元素

时间:2012-07-01 19:59:42

标签: ruby arrays random sample shuffle

我知道我可以使用样本方法从数组中选择一个随机元素,但这样就可以不止一次地拾取元素。我可以先将数组洗牌,然后按顺序从第一个元素到最后一个元素,但我知道这是内存密集型的,如果可能的话,我正在寻找一种不太密集的方法!

4 个答案:

答案 0 :(得分:10)

sample接受论证:

[*(1..10)].sample(5) #=>[3, 4, 1, 8, 9] 

两次都不会选择任何元素。

答案 1 :(得分:8)

对阵列进行混洗不是内存密集型的。 Ruby有一个默认的shuffle实现,它被称为Array.shuffle!。查看源代码,您可以看到(它是C):

rb_ary_shuffle_bang(ary)
    VALUE ary;
{
    long i = RARRAY(ary)->len;

    rb_ary_modify(ary);
    while (i) {
        long j = rb_genrand_real()*i;
        VALUE tmp = RARRAY(ary)->ptr[--i];
        RARRAY(ary)->ptr[i] = RARRAY(ary)->ptr[j];
        RARRAY(ary)->ptr[j] = tmp;
    }
    return ary;
}

此实现遵循经典Fisher-Yates algorithm

所以:

  1. 使用shuffle!将阵列移动到位。时间复杂度为O(n),无需额外内存。
  2. 迭代数组。时间复杂度为O(n),不需要额外的内存(只有一个整数来保存当前索引)。
  3. 总体而言,您拥有所需的内容,没有额外的内存和时间复杂度O(n)

答案 2 :(得分:1)

如果数组元素真的非常大,你可以尝试简单地混合索引列表并迭代它:

a = %w{a b c d e f g h}

[*0...a.size].shuffle.each do |index|
  puts a[index]
end

答案 3 :(得分:0)

您必须跟踪您已选择的元素;你要做什么,把它们放在自己的阵列中?

随机播放和迭代。与跟踪已选择的元素相比,这不会占用更多内存。