Improve this recursive code please!
Anton Vredegoor
anton at vredegoor.doge.nl
Fri May 9 17:30:25 EDT 2003
"Sean Ross" <frobozz_electric at hotmail.com> wrote:
>I've been thinking about this problem for several days. Unfortunately, I
>haven't found a solution for you, but I have found the form of a solution
>that perhaps someone else here will know how to implement:
>
>for arrangement in xuniquepermute(xdistribute(items, bins)):
> print arrangement # or perform some other operations with this
>arrangement
Yes, I have been thinking about this too and I've even posted a crude
solution following this line of reasoning. However, before going on I
must point out that there's already a better way to do it (this
generates the arrangements in sorted order):
#an edited version of Steven Taschuk's solution
def findarrangements(bricksleft, binsleft, bins = []):
if binsleft > 1:
# More than one bin left, and we need to distribute
# bricksleft bricks among them.
for n in range(bricksleft+1):
# Find arrangements in which next bin has n bricks.
bins.append(n)
for x in findarrangements(bricksleft-n, binsleft-1, bins):
yield x
bins.pop()
else:
# Only one bin left; put all remaining bricks there.
bins.append(bricksleft)
yield bins
bins.pop()
def test():
for x in findarrangements(4,4):
print x
if __name__=='__main__':
test()
>I haven't been able to implement either xdistribute() or xuniquepermute()
>myself, although I will keep trying because I think the idea is sound and
>would work as a solution to your problem. I would be relieved to see an
>implementation of this, as it's become something of an itch for me.
Since it's requested I'll share my recent explorations. I've even
started a separate thread where I'am asking info about turning
recursive functions into generators to enable this solution. It now
also involves conjugating partitions in order to generate only those
partitions that consist of no more parts than the number of bins. I'm
still working on producing indexed partitions instead of generated
ones. The unique permutes are already generated by index. Premature
optimizations won't stop this coder :-P
Anton
def starters(L):
#return a list of 2-tuples containing info about list L
n,np,R = len(L),1,range(len(L))
bf = [L[:i].count(L[i]) for i in R]
for i in R: np = np*(n-i)/(bf[i]+1)
for i in R:
if not bf[i]:
yield i,np*L[i:].count(L[i])/n
def uniquepermute(L,index=0):
#return an uniquepermute of list L
remain, res, T = index, [], L[:]
while T:
for j,k in starters(T):
if remain-k < 0:
res.append(T.pop(j))
break
remain -= k
return res
def nperm(L):
#return the number of possible uniquepermutes of list L
n,np,R = len(L),1,range(len(L))
bf = [L[:i].count(L[i]) for i in R]
for i in R: np = np*(n-i)/(bf[i]+1)
return np
def conjPartition(a):
#conjugate a partition
n,b = len(a),[1]*a[0]
for j in range(1,n):
for i in range(a[j]):
b[i]+=1
return b
def genPartitions(m,n):
#generate all partitions of m into n parts
a = [n]*m
def recPartition(m,B,N):
#recursive partition function
if m == 0:
yield conjPartition(a[:N])
else:
for i in range(1,min(B,m)+1):
a[N]=i
for p in recPartition(m-i,i,N+1): yield p
for p in recPartition(m-n,n,1): yield p
def findArrangements(m,n):
#generate all arrangements of m into n
pad = [0] *(n-1)
for i in range(1,n+1):
for p in genPartitions(m,i):
b = p + pad
for j in range(nperm(b)):
yield uniquepermute(b,j)
pad = pad[0:-1]
def test():
for x in findArrangements(4,4):
print x
if __name__=='__main__':
test()
More information about the Python-list
mailing list