Understanding the source code for Ruby's repeated_permutation method

那年仲夏 提交于 2019-12-06 08:14:33

The code you linked calls rpermute0 which does most the work, source code for rpermute0 in Array.c is

static void
rpermute0(long n, long r, long *p, long index, VALUE values)
{
    long i, j;
    for (i = 0; i < n; i++) {
    p[index] = i;
    if (index < r-1) {              /* if not done yet */
        rpermute0(n, r, p, index+1, values); /* recurse */
    }
    else {
        /* We have a complete permutation of array indexes */
        /* Build a ruby array of the corresponding values */
        /* And yield it to the associated block */
        VALUE result = rb_ary_new2(r);
        VALUE *result_array = RARRAY_PTR(result);
        const VALUE *values_array = RARRAY_PTR(values);

        for (j = 0; j < r; j++) result_array[j] = values_array[p[j]];
        ARY_SET_LEN(result, r);
        rb_yield(result);
        if (RBASIC(values)->klass) {
        rb_raise(rb_eRuntimeError, "repeated permute reentered");
        }
    }
    }
}

Basially a brute force, starting from 0 returning one permutation each iteration. ruby version is something like

require 'pp'

def rpermute(numRepeat, pArray, index, originArray)
  0.upto(originArray.length-1) do |i|
    pArray[index] = i
    if index < numRepeat-1
      rpermute(numRepeat, pArray, index+1, originArray)
    else
      result = Array.new
      0.upto(numRepeat-1) do |j|
        result[j] = originArray[pArray[j]]
      end
     pp result
    end
  end
end

originArray1 = [1,2,3,4,5]
originArray2 = ['a','b','c','d','e']
pArray = []

rpermute(4, pArray, 0, originArray1)
rpermute(4, pArray, 0, originArray2)

I tested above code and it prints out all permutation of length 4, u might want to put them into array.

Thanks yngum!

Just to expand on your answer, I renamed some variables to make it more Ruby-esque, more clear, descriptive, and explicit. I also changed a few things so the return value of the method would be the answer, an array that contains each of the possible permutations.

def repeated_permutations(original_array, length_of_each_permutation, list_of_permutations, index_positions, index)
    0.upto(original_array.length - 1) do |index1|
        index_positions[index] = index1
        if index < length_of_each_permutation - 1
            repeated_permutations(original_array, length_of_each_permutation, list_of_permutations, index_positions, index + 1)
        else
            permutation = Array.new
            0.upto(length_of_each_permutation - 1) do |index2|
                permutation[index2] = original_array[index_positions[index2]]
            end 
            list_of_permutations.push(permutation)
        end
    end
    list_of_permutations
end

I don't love naming it index_positions, but couldn't think of a better name. The above method will return an array filled with arrays of all possible permutations with repetition allowed.

To implement:

valid_colors = %w(red orange blue green purple yellow) repeated_permutations(valid_colors, 4, [], [], 0)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!