This question is not clear. Firstly, the title, which is vague, asks how a particular approach to an unstated problem can be implemented. What you need, at the beginning, is a statement in words of the problem.
I will make a guess as to what that statement might be and then propose a solution.
Given
- an array
arr
;
- a positive integer
n
, 1 <= n <= arr.size
; and
- a method
m
having n
arguments that are distinct elements of arr
that returns true
or false
,
what combinations of n
elements of arr
cause m
to return true
?
We can use the following method combined with a definition of the method m
.
def combos(arr, n, m)
arr.combination(n).select { |x| public_send(m, *x) }
end
The key, of course, is the method Array#combination. See also the docs for the methods Enumerable#select and Object#public_send.
Here is its use with the example given in the question.
def m(*x)
x.sum.odd?
end
arr = [1,2,3,4,5,6]
combos(arr, 2, :m)
#=> [[1, 2], [1, 4], [1, 6], [2, 3], [2, 5], [3, 4], [3, 6], [4, 5], [5, 6]]
combos(arr, 3, :m)
#=> [[1, 2, 4], [1, 2, 6], [1, 3, 5], [1, 4, 6], [2, 3, 4], [2, 3, 6],
# [2, 4, 5], [2, 5, 6], [3, 4, 6], [4, 5, 6]]
combos(arr, 4, :m)
#=> [[1, 2, 3, 5], [1, 2, 4, 6], [1, 3, 4, 5], [1, 3, 5, 6], [2, 3, 4, 6], [2, 4, 5, 6]]
See the doc for Array#sum (which made it's debut in Ruby v2.4.
Here's a second example: given an array of letters, which combinations of five letters have two vowels?
VOWEL_COUNTER = %w| a e i o u |.product([1]).to_h.tap { |h| h.default=0 }
#=> {"a"=>1, "e"=>1, "i"=>1, "o"=>1, "u"=>1}
VOWEL_COUNTER['a']
#=> 1
By setting the hash's default value to zero, VOWEL_COUNTER[k]
will return zero if it does not have a key k
. For example,
VOWEL_COUNTER['r']
#=> 0
def m(*x)
x.sum { |c| VOWEL_COUNTER[c] } == 2
end
arr = %w| a r t u e v s |
combos(arr, 5, :m)
#=> [["a", "r", "t", "u", "v"], ["a", "r", "t", "u", "s"],
# ["a", "r", "t", "e", "v"], ["a", "r", "t", "e", "s"],
# ["a", "r", "u", "v", "s"], ["a", "r", "e", "v", "s"],
# ["a", "t", "u", "v", "s"], ["a", "t", "e", "v", "s"],
# ["r", "t", "u", "e", "v"], ["r", "t", "u", "e", "s"],
# ["r", "u", "e", "v", "s"], ["t", "u", "e", "v", "s"]]
Note that VOWEL_COUNTER
is constructed as follows.
a = %w| a e i o u |
#=> ["a", "e", "i", "o", "u"]
b = a.product([1])
#=> [["a", 1], ["e", 1], ["i", 1], ["o", 1], ["u", 1]]
c = b.to_h
#=> {"a"=>1, "e"=>1, "i"=>1, "o"=>1, "u"=>1}
With this hash,
c['r']
#=> nil
so we need to set the default value to zero.
VOWEL_COUNTER = c.tap { |h| h.default=0 }
#=> {"a"=>1, "e"=>1, "i"=>1, "o"=>1, "u"=>1}
c['r']
#=> 0
Alternatively, we could have omitted the last step (setting the hash's default to zero), and written
x.sum { |c| VOWEL_COUNTER[c].to_i } == 2
because NilClass#to_i converts nil
to zero.
See also the docs for the methods #select, #public_send