mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	* array.c (rb_ary_combination): new method to give all combination
of elements from an array. [ruby-list:42671] * array.c (rb_ary_product): a new method to get all combinations of elements from two arrays. can be extended to combinations of n-arrays, e.g. a.product(b,c,d). anyone volunteer? * array.c (rb_ary_permutation): empty function body to calculate permutations of array elements. need volunteer. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13568 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
		
							parent
							
								
									0d07755472
								
							
						
					
					
						commit
						43c4d80930
					
				
					 4 changed files with 175 additions and 1 deletions
				
			
		
							
								
								
									
										12
									
								
								ChangeLog
									
										
									
									
									
								
							
							
						
						
									
										12
									
								
								ChangeLog
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,3 +1,15 @@
 | 
			
		|||
Sat Sep 29 17:31:04 2007  Yukihiro Matsumoto  <matz@ruby-lang.org>
 | 
			
		||||
 | 
			
		||||
	* array.c (rb_ary_combination): new method to give all combination
 | 
			
		||||
	  of elements from an array.  [ruby-list:42671]
 | 
			
		||||
 | 
			
		||||
	* array.c (rb_ary_product): a new method to get all combinations
 | 
			
		||||
	  of elements from two arrays.  can be extended to combinations of
 | 
			
		||||
	  n-arrays, e.g. a.product(b,c,d).  anyone volunteer?
 | 
			
		||||
 | 
			
		||||
	* array.c (rb_ary_permutation): empty function body to calculate
 | 
			
		||||
	  permutations of array elements.  need volunteer.
 | 
			
		||||
 | 
			
		||||
Sat Sep 29 17:14:44 2007  Yukihiro Matsumoto  <matz@ruby-lang.org>
 | 
			
		||||
 | 
			
		||||
	* marshal.c (r_leave): move proc invocation from r_entry() to
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										140
									
								
								array.c
									
										
									
									
									
								
							
							
						
						
									
										140
									
								
								array.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -2954,6 +2954,143 @@ rb_ary_cycle(VALUE ary)
 | 
			
		|||
    return Qnil;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static long
 | 
			
		||||
perm_len(long n, long k)
 | 
			
		||||
{
 | 
			
		||||
    long i, val = 1;
 | 
			
		||||
 | 
			
		||||
    while (n > k) {
 | 
			
		||||
	val *= n--;
 | 
			
		||||
    }
 | 
			
		||||
    return val;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  call-seq:
 | 
			
		||||
 *     ary.permutation(n)
 | 
			
		||||
 *  
 | 
			
		||||
 *  Returns an array of all permutations of length <i>n</i> of
 | 
			
		||||
 *  elements from <i>ary</i>].
 | 
			
		||||
 *     
 | 
			
		||||
 *     a = [1, 2, 3]
 | 
			
		||||
 *     a.permutation(0).to_a  #=> []
 | 
			
		||||
 *     a.permutation(1).to_a  #=> [[1],[2],[3]]
 | 
			
		||||
 *     a.permutation(2).to_a  #=> [[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]]
 | 
			
		||||
 *     a.permutation(3).to_a  #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
 | 
			
		||||
 *     a.permutation(4).to_a  #=> []
 | 
			
		||||
 *     
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static VALUE
 | 
			
		||||
rb_ary_permutation(VALUE ary, VALUE num)
 | 
			
		||||
{
 | 
			
		||||
    /* TBD */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static long
 | 
			
		||||
combi_len(long n, long k)
 | 
			
		||||
{
 | 
			
		||||
    long i, val = 1;
 | 
			
		||||
 | 
			
		||||
    if (k*2 > n) k = n-k;
 | 
			
		||||
    if (k == 0) return 1;
 | 
			
		||||
    if (k < 0) return 0;
 | 
			
		||||
    val = 1;
 | 
			
		||||
    for (i=1; i <= k; i++,n--) {
 | 
			
		||||
	val *= n;
 | 
			
		||||
	val /= i;
 | 
			
		||||
    }
 | 
			
		||||
    return val;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  call-seq:
 | 
			
		||||
 *     ary.combination(n)
 | 
			
		||||
 *  
 | 
			
		||||
 *  Returns an enumerator of all combinations of length <i>n</i> of
 | 
			
		||||
 *  elements from <i>ary</i>].
 | 
			
		||||
 *     
 | 
			
		||||
 *     a = [1, 2, 3, 4]
 | 
			
		||||
 *     a.combination(0).to_a  #=> []
 | 
			
		||||
 *     a.combination(1).to_a  #=> [[1],[2],[3],[4]]
 | 
			
		||||
 *     a.combination(2).to_a  #=> [[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]
 | 
			
		||||
 *     a.combination(3).to_a  #=> [[1,2,3],[1,2,4],[1,3,4],[2,3,4]]
 | 
			
		||||
 *     a.combination(4).to_a  #=> [[1,2,3,4]]
 | 
			
		||||
 *     a.combination(5).to_a  #=> []
 | 
			
		||||
 *     
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static VALUE
 | 
			
		||||
rb_ary_combination(VALUE ary, VALUE num)
 | 
			
		||||
{
 | 
			
		||||
    long n, i, len;
 | 
			
		||||
 | 
			
		||||
    RETURN_ENUMERATOR(ary, 1, &num);
 | 
			
		||||
    n = NUM2LONG(num);
 | 
			
		||||
    len = RARRAY_LEN(ary);
 | 
			
		||||
    if (n < 1 || len < n) {
 | 
			
		||||
	/* yield nothing */
 | 
			
		||||
    }
 | 
			
		||||
    else if (n == 0) {
 | 
			
		||||
	for (i = 0; i < len; i++) {
 | 
			
		||||
	    rb_yield(rb_ary_new2(0));
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
    else if (n == 1) {
 | 
			
		||||
	for (i = 0; i < len; i++) {
 | 
			
		||||
	    rb_yield(rb_ary_new3(1, RARRAY_PTR(ary)[i]));
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
	volatile VALUE tmp = rb_str_new(0, n*sizeof(long));
 | 
			
		||||
	long *stack = (long*)RSTRING_PTR(tmp);
 | 
			
		||||
	long nlen = combi_len(len, n);
 | 
			
		||||
	volatile VALUE cc = rb_ary_new2(n);
 | 
			
		||||
	VALUE *chosen = RARRAY_PTR(cc);
 | 
			
		||||
	long lev = 0;
 | 
			
		||||
 | 
			
		||||
	MEMZERO(stack, long, n);
 | 
			
		||||
	stack[0] = -1;
 | 
			
		||||
	for (i = 0; i < nlen; i++) {
 | 
			
		||||
	    chosen[lev] = RARRAY_PTR(ary)[stack[lev+1]];
 | 
			
		||||
	    for (lev++; lev < n; lev++) {
 | 
			
		||||
		chosen[lev] = RARRAY_PTR(ary)[stack[lev+1] = stack[lev]+1];
 | 
			
		||||
	    }
 | 
			
		||||
	    rb_yield(rb_ary_new4(n, chosen));
 | 
			
		||||
	    do {
 | 
			
		||||
		stack[lev--]++;
 | 
			
		||||
	    } while (lev && (stack[lev+1]+n == len+lev+1));
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
    return ary;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  call-seq:
 | 
			
		||||
 *     ary.product(ary2)
 | 
			
		||||
 *  
 | 
			
		||||
 *  Returns an array of all combinations of elements from both arrays.
 | 
			
		||||
 *     
 | 
			
		||||
 *     [1,2,3].product([4,5])  #=> [[1,4],[1,5],[2,4],[2,5],[3,4],[3,5]]
 | 
			
		||||
 *     [1,2].product([1,2])    #=> [[1,1],[1,2],[2,1],[2,2]]
 | 
			
		||||
 *     
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static VALUE
 | 
			
		||||
rb_ary_product(VALUE ary, VALUE a2)
 | 
			
		||||
{
 | 
			
		||||
    VALUE result = rb_ary_new2(RARRAY_LEN(ary));
 | 
			
		||||
    long i, j;
 | 
			
		||||
 | 
			
		||||
    for (i=0; i<RARRAY_LEN(ary); i++) {
 | 
			
		||||
	for (j=0; j<RARRAY_LEN(a2); j++) {
 | 
			
		||||
	    rb_ary_push(result, rb_ary_new3(2, rb_ary_entry(ary, i),
 | 
			
		||||
					       rb_ary_entry(a2, j)));
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Arrays are ordered, integer-indexed collections of any object. 
 | 
			
		||||
 * Array indexing starts at 0, as in C or Java.  A negative index is 
 | 
			
		||||
 * assumed to be relative to the end of the array---that is, an index of -1 
 | 
			
		||||
| 
						 | 
				
			
			@ -3052,6 +3189,9 @@ Init_Array(void)
 | 
			
		|||
    rb_define_method(rb_cArray, "shuffle", rb_ary_shuffle, 0);
 | 
			
		||||
    rb_define_method(rb_cArray, "choice", rb_ary_choice, 0);
 | 
			
		||||
    rb_define_method(rb_cArray, "cycle", rb_ary_cycle, 0);
 | 
			
		||||
    /* rb_define_method(rb_cArray, "permutation", rb_ary_permutation, 1); */
 | 
			
		||||
    rb_define_method(rb_cArray, "combination", rb_ary_combination, 1);
 | 
			
		||||
    rb_define_method(rb_cArray, "product", rb_ary_product, 1);
 | 
			
		||||
 | 
			
		||||
    id_cmp = rb_intern("<=>");
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								string.c
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								string.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -2872,6 +2872,7 @@ rb_str_inspect(VALUE str)
 | 
			
		|||
    char *p, *pend;
 | 
			
		||||
    VALUE result = rb_str_buf_new2("");
 | 
			
		||||
 | 
			
		||||
    rb_enc_associate(result, enc);
 | 
			
		||||
    str_cat_char(result, '"', enc);
 | 
			
		||||
    p = RSTRING_PTR(str); pend = RSTRING_END(str);
 | 
			
		||||
    while (p < pend) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2928,7 +2929,6 @@ rb_str_inspect(VALUE str)
 | 
			
		|||
    str_cat_char(result, '"', enc);
 | 
			
		||||
 | 
			
		||||
    OBJ_INFECT(result, str);
 | 
			
		||||
    rb_enc_associate(result, enc);
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1177,4 +1177,26 @@ class TestArray < Test::Unit::TestCase
 | 
			
		|||
    assert_equal(@cls[1,2], @cls[1, 2] | @cls[1, 2])
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
# def test_permutation
 | 
			
		||||
#    assert_equal(@cls[], @cls[1,2,3].permutation(0).to_a)
 | 
			
		||||
#    assert_equal(@cls[[1],[2],[3]], @cls[1,2,3].permutation(1).to_a)
 | 
			
		||||
#    assert_equal(@cls[[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]], @cls[1,2,3].permutation(2).to_a)
 | 
			
		||||
#    assert_equal(@cls[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]], @cls[1,2,3].permutation(3).to_a)
 | 
			
		||||
#    assert_equal(@cls[], @cls[1,2,3].permutation(4).to_a)
 | 
			
		||||
#  end
 | 
			
		||||
 | 
			
		||||
 def test_combination
 | 
			
		||||
    assert_equal(@cls[], @cls[1,2,3,4].combination(0).to_a)
 | 
			
		||||
    assert_equal(@cls[[1],[2],[3],[4]], @cls[1,2,3,4].combination(1).to_a)
 | 
			
		||||
    assert_equal(@cls[[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]], @cls[1,2,3,4].combination(2).to_a)
 | 
			
		||||
    assert_equal(@cls[[1,2,3],[1,2,4],[1,3,4],[2,3,4]], @cls[1,2,3,4].combination(3).to_a)
 | 
			
		||||
    assert_equal(@cls[[1,2,3,4]], @cls[1,2,3,4].combination(4).to_a)
 | 
			
		||||
    assert_equal(@cls[], @cls[1,2,3,4].combination(5).to_a)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_product
 | 
			
		||||
    assert_equal(@cls[[1,4],[1,5],[2,4],[2,5],[3,4],[3,5]],
 | 
			
		||||
                 @cls[1,2,3].product([4,5]))
 | 
			
		||||
    assert_equal(@cls[[1,1],[1,2],[2,1],[2,2]], @cls[1,2].product([1,2]))
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue