Tuesday, July 5, 2011

Iterative algorithm for generating permutations from sets' single elements

My friend asked on facebook for a iterative algorihm that would generate all possible strings from given sets in a way that for ex. given {a,b,c}, {d,e}, {f} should produce {adf, aef, bdf, bef, cdf, cef}.

def permute(*args)
# initialize the register for each array
# with [array itself, offset, its size]
memory = []
perm_count = 1
args.each do |array|
size = array.size
memory << [array, 0, size-1]
# get the number of all combinations
perm_count *= size
end
# remember the memory size
msize = memory.size
result = []
# for every possible permutation
perm_count.times do |i|
# prepare empty array and bumped flag
permutation = []
bumped = false
# iterate over subsets
msize.times do |j|
# get element with a registered offset
permutation.push(memory[j][0][memory[j][1]])
# if no offset was bumped yet, bump one
unless bumped
# the current one
if memory[j][1] < memory[j][2]
memory[j][1] += 1
bumped = true
else
# or any next possible one that will not overflow yet
# and set the current offset to 0
memory[j][1] = 0
bump_next(memory, j)
bumped = true
end
end
end
# save the permutation to the results array
result << permutation.join
end
result
end
# finiding the one that can be bumped
def bump_next(memory, j)
n = j+1
unless memory[n].nil?
unless full?(memory[n])
memory[n][1] += 1
else
memory[n][1] = 0
bump_next(memory, n)
end
end
end
# check if the offset doesn't overflow
def full?(array)
array[1]==array[2]
end
view raw permset.rb hosted with ❤ by GitHub


There is still a recursive call moved to bump_next method. I'm trying to get rid of that one and make it fully iterative.
That was much fun doing it, as it has some tricky parts. Probably faster algorithm for that already exists, but I couldn't find any. Lots of fun.

No comments:

Post a Comment