require 'facets/core/integer/factorial' module Enumerable # Permutation proves the possible orders of an enumerable. # Each is index by a oermutation numnber. The maximum number of # arrangements is the factorial of the size of the array. def permutation(number) arr = to_a out = arr[0..0] nextfactor = factor = 1 arr.each_with_index {|x,i| case i when 0: next else nextfactor = factor * (i+1) out.insert(number % nextfactor / factor, x) factor = nextfactor end } out end alias :permute :permutation # def permutation_number(original_array=self.to_a.sort) arr = to_a m = 1 v = 0 last_indicies = Hash.new(0) original_array.each_with_index {|x,i| next if i==0 m *= i done = original_array[0..i] v += m * arr.select {|y| done.include?(y)}.rindex(x) } v end # Applys a block to each possible permutation of an array/enumerable. # # %w[a b c].each_permutation { |x| puts(x.join('')) } # # produces # # abc # acb # bac # bca # cab # cba # def each_permutation() arr = to_a size = arr.size perm_count = (1...size).inject(0) { |s,x| s + x * x.factorial } weights = Array.new(size-1) {|i| (i+1).factorial } s = weights.size x,i,v,pos = nil 0.upto(perm_count) do |v| out = arr[0..0] arr.each_with_index {|x,i| case i when 0: next when s: out.insert(v / weights[i-1], x) else out.insert(v % weights[i] / weights[i-1], x) end } yield out end end #-- OLD VERSION #def each_permutation( prefixed=[] ) # s = self.to_a # if (length < 2) # # there are no elements left to permute # yield(prefixed + self) # else # # recursively permute the remaining elements # s.each_with_index do |e, i| # (s[0,i]+s[(i+1)..-1]).each_permutation(prefixed+[e]) { |a| yield a } # end # end #end #++ end # _____ _ # |_ _|__ __| |_ # | |/ -_|_-< _| # |_|\___/__/\__| # =begin test require 'test/unit' require 'set' class TCEnumerable < Test::Unit::TestCase def test_001 o = Set.new %w[a b c].each_permutation { |x| o << x.join('') } r = Set.new(['abc','acb','bac','bca','cab','cba']) assert_equal( r, o ) end end =end # ___ _ # / __| |_ __ _ _ _ __ _ ___ ___ # | (__| ' \/ _` | ' \/ _` / -_|_-< # \___|_||_\__,_|_||_\__, \___/__/ # |___/ # =begin changelog 2005-10-05 (trans): - Changed 'Class Array' to 'module Enumerable' - Replaced with Daniel Sheppard's code. =end # ___ _ _ _ # / __|_ _ ___ __| (_) |_ ___ # | (__| '_/ -_) _` | | _(_-< # \___|_| \___\__,_|_|\__/__/ # =begin credits - Daniel Sheppard - Paul Battley (old version of each_permutation) =end