Add `Array#{permutation,combination}.

parent f2394859
......@@ -2,4 +2,5 @@ MRuby::Gem::Specification.new('mruby-array-ext') do |spec|
spec.license = 'MIT'
spec.author = 'mruby developers'
spec.summary = 'Array class extension'
spec.add_test_dependency 'mruby-enumerator', core: 'mruby-enumerator'
end
......@@ -808,4 +808,100 @@ class Array
n
end
end
##
# call-seq:
# ary.permutation { |p| block } -> ary
# ary.permutation -> Enumerator
# ary.permutation(n) { |p| block } -> ary
# ary.permutation(n) -> Enumerator
#
# When invoked with a block, yield all permutations of length +n+ of the
# elements of the array, then return the array itself.
#
# If +n+ is not specified, yield all permutations of all elements.
#
# The implementation makes no guarantees about the order in which the
# permutations are yielded.
#
# If no block is given, an Enumerator is returned instead.
#
# Examples:
#
# a = [1, 2, 3]
# a.permutation.to_a #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
# 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(0).to_a #=> [[]] # one permutation of length 0
# a.permutation(4).to_a #=> [] # no permutations of length 4
def permutation(n=self.size, &block)
size = self.size
return to_enum(:permutation, n) unless block
return if n > size
if n == 0
yield []
else
i = 0
while i<size
result = [self[i]]
if n-1 > 0
ary = self[0...i] + self[i+1..-1]
ary.permutation(n-1) do |c|
yield result + c
end
else
yield result
end
i += 1
end
end
end
##
# call-seq:
# ary.combination(n) { |c| block } -> ary
# ary.combination(n) -> Enumerator
#
# When invoked with a block, yields all combinations of length +n+ of elements
# from the array and then returns the array itself.
#
# The implementation makes no guarantees about the order in which the
# combinations are yielded.
#
# If no block is given, an Enumerator is returned instead.
#
# Examples:
#
# a = [1, 2, 3, 4]
# 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(0).to_a #=> [[]] # one combination of length 0
# a.combination(5).to_a #=> [] # no combinations of length 5
def combination(n, &block)
size = self.size
return to_enum(:combination, n) unless block
return if n > size
if n == 0
yield []
elsif n == 1
i = 0
while i<size
yield [self[i]]
i += 1
end
else
i = 0
while i<size
result = [self[i]]
self[i+1..-1].combination(n-1) do |c|
yield result + c
end
i += 1
end
end
end
end
......@@ -381,3 +381,31 @@ assert("Array#slice!") do
assert_equal(i, [1, 2, 3])
assert_equal(j, nil)
end
assert("Array#permutation") do
a = [1, 2, 3]
assert_equal([[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]],
a.permutation.to_a)
assert_equal([[1],[2],[3]],
a.permutation(1).to_a)
assert_equal([[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]],
a.permutation(2).to_a)
assert_equal([[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]],
a.permutation(3).to_a)
assert_equal([[]], a.permutation(0).to_a)
assert_equal([], a.permutation(4).to_a)
end
assert("Array#combination") do
a = [1, 2, 3, 4]
assert_equal([[1],[2],[3],[4]],
a.combination(1).to_a)
assert_equal([[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]],
a.combination(2).to_a)
assert_equal([[1,2,3],[1,2,4],[1,3,4],[2,3,4]],
a.combination(3).to_a)
assert_equal([[1,2,3,4]],
a.combination(4).to_a)
assert_equal([[]], a.combination(0).to_a)
assert_equal([], a.combination(5).to_a)
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment