Reputation: 329
I need to implement a function which gets a array with Symbols as parameters like [:a :b :c]
, and then returns a array which contains all possible permutations of boolean values mapped to those symbols in a hash
like
[{a: true, b: true, c: true},
{a: false, b: true, c: true},
{a: true, b: false, c: true},
{a: true, b: true, c: false},
{a: true, b: false, c: false},
{a: false, b: false, c: true},
{a: false, b: true, c: false},
{a: false, b: false, c: false}]
what is a elegant way to implement such a thing in ruby?
Upvotes: 3
Views: 2326
Reputation: 110665
Another way is to use recursion:
def permute(arr)
first, *rest = arr
return [{ first=>:true }, { first=>:false }] if rest.empty?
permute(rest).flat_map { |h| [{ first=>:true }.merge(h), { first=>:false }.merge(h)] }
end
permute([:a, :b, :c])
#=> [{:a=>:true, :b=>:true, :c=>:true }, {:a=>:false, :b=>:true, :c=>:true },
# {:a=>:true, :b=>:false, :c=>:true }, {:a=>:false, :b=>:false, :c=>:true },
# {:a=>:true, :b=>:true, :c=>:false}, {:a=>:false, :b=>:true, :c=>:false},
# {:a=>:true, :b=>:false, :c=>:false}, {:a=>:false, :b=>:false, :c=>:false}]
Upvotes: 2
Reputation: 18762
We can take advantage of fact that pattern of true
/false
in output hash follows binary number sequence between 0 to (2ary.size-1), and do something like below
require "pp"
ary = [:a,:b,:c]
result = (0...2**ary.size).map do |num|
bool_array = (0...ary.size).map do |bit_pos|
num[bit_pos].zero?
end
ary.zip(bool_array).to_h
end
pp result
#=> [{:a=>false, :b=>false, :c=>false},
# {:a=>true, :b=>false, :c=>true},
# {:a=>false, :b=>true, :c=>true},
# {:a=>true, :b=>true, :c=>true},
# {:a=>false, :b=>false, :c=>false},
# {:a=>true, :b=>false, :c=>true},
# {:a=>false, :b=>true, :c=>true},
# {:a=>true, :b=>true, :c=>true}]
Upvotes: 4
Reputation: 114138
I use repeated_permutation
for this task:
[true, false].repeated_permutation(3)
.map { |a, b, c| { a: a, b: b, c: c } }
#=> [{:a=>true, :b=>true, :c=>true},
# {:a=>true, :b=>true, :c=>false},
# {:a=>true, :b=>false, :c=>true},
# {:a=>true, :b=>false, :c=>false},
# {:a=>false, :b=>true, :c=>true},
# {:a=>false, :b=>true, :c=>false},
# {:a=>false, :b=>false, :c=>true},
# {:a=>false, :b=>false, :c=>false}]
or with an array of keys:
keys = %i(a b c)
[true, false].repeated_permutation(keys.size)
.map { |values| keys.zip(values).to_h }
Upvotes: 10