473,406 Members | 2,217 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,406 software developers and data experts.

new itertools functions in Python 2.6

With the new functions added to itertools in Python 2.6,
I can finally get rid of this monstrosity:

def ooloop6(a, n, perm=True, repl=True):
if (not repl) and (n>len(a)): return
r0 = range(n)
r1 = r0[1:]
if perm and repl: # ok
v = ','.join(['c%s' % i for i in r0])
f = ' '.join(['for c%s in a' % i for i in r0])
e = ''.join(["p = [''.join((",v,")) ",f,"]"])
exec e
return p
if (not perm) and repl: # ok
v = ','.join(['c%s' % i for i in r0])
f = ' '.join(['for c%s in a' % i for i in r0])
i = ' and '.join(['(c%s>=c%s)' % (j,j-1) for j in r1])
e = ''.join(["p = [''.join((",v,")) ",f," if ",i,"]"])
exec e
return p
if perm and (not repl): # ok
v = ','.join(['c%s' % i for i in r0])
f = ' '.join(['for c%s in a' % i for i in r0])
i = ' and '.join([' and '.join(['(c%s!=c%s)' % (j,k) for k in
range(j)]) for j in r1])
e = ''.join(["p = [''.join((",v,")) ",f," if ",i,"]"])
exec e
return p
if (not perm) and (not repl): # ok
v = ','.join(['c%s' % i for i in r0])
f = ' '.join(['for c%s in a' % i for i in r0])
i = ' and '.join(['(c%s>c%s)' % (j,j-1) for j in r1])
e = ''.join(["p = [''.join((",v,")) ",f," if ",i,"]"])
exec e
return p

If I use a single iterable with the repeat option,
the Carteisan Product will give me Permutaions With Replacement.

from itertools import *
from math import factorial as fac

s = 'abcde'
m = len(s)
n = 3

print 'For %d letters (%s) taken %d at a time:' % (m,s,n)
print '========================================'

### Permutations with replacement m**n
###
print 'Permutations with replacement'
print '-----------------------------'
p = [i for i in product('abcde',repeat=3)]
for i in p:
print ''.join(i),
print
print
print 'actual words: %d m**n words: %d' % (len(p),m**n)
print

## For 5 letters (abcde) taken 3 at a time:
## ========================================
## Permutations with replacement
## -----------------------------
## aaa aab aac aad aae aba abb abc abd abe aca acb
## acc acd ace ada adb adc add ade aea aeb aec aed
## aee baa bab bac bad bae bba bbb bbc bbd bbe bca
## bcb bcc bcd bce bda bdb bdc bdd bde bea beb bec
## bed bee caa cab cac cad cae cba cbb cbc cbd cbe
## cca ccb ccc ccd cce cda cdb cdc cdd cde cea ceb
## cec ced cee daa dab dac dad dae dba dbb dbc dbd
## dbe dca dcb dcc dcd dce dda ddb ddc ddd dde dea
## deb dec ded dee eaa eab eac ead eae eba ebb ebc
## ebd ebe eca ecb ecc ecd ece eda edb edc edd ede
## eea eeb eec eed eee
##
## actual words: 125 m**n words: 125
So what does "permutaions" mean in itertools?
It actually means Permutions Without Replacement.

### Permutations without replacement m!/(m-n)!
###
print 'Permutations without replacement'
print '--------------------------------'
p = [i for i in permutations('abcde',3)]
for i in p:
print ''.join(i),
print
print
print 'actual words: %d m!/(m-n)! words: %d' % (len(p),fac(m)/fac(m-
n))
print

## Permutations without replacement
## --------------------------------
## abc abd abe acb acd ace adb adc ade aeb aec aed
## bac bad bae bca bcd bce bda bdc bde bea bec bed
## cab cad cae cba cbd cbe cda cdb cde cea ceb ced
## dab dac dae dba dbc dbe dca dcb dce dea deb dec
## eab eac ead eba ebc ebd eca ecb ecd eda edb edc
##
## actual words: 60 m!/(m-n)! words: 60
Not surprisingly, "combinations" actually means
Combinations Without Replacement.

### Combinations without replacement m!/(n!(m-n)!)
###
print 'Combinations without replacement'
print '--------------------------------'
p = [i for i in combinations('abcde',3)]
for i in p:
print ''.join(i),
print
print
print 'actual words: %d m!/(n!(m-n)!) words: %d' % (len(p),fac(m)/
(fac(n)*factorial(m-n)))
print

## Combinations without replacement
## --------------------------------
## abc abd abe acd ace ade bcd bce bde cde
##
## actual words: 10 m!/(n!(m-n)!) words: 10
Hmm...that's only three subsets of the Cartesian Product.
No Combinations With Replacement.

Although you can always filter the Cartesian Product to
get a subset.

# Combinations with replacement (m+n-1)!/(n!(m-1)!)
#
print 'Combinations with replacement'
print '-----------------------------'
p = [i for i in ifilter(lambda x:
list(x)==sorted(x),product('abcde',repeat=3))]
for i in p:
print ''.join(i),
print
print
print 'actual words: %d (m+n-1)!/(n!(m-1)!) words: %d' %
(len(p),fac(m+n-1)/(fac(n)*fac(m-1)))
print

## Combinations with replacement
## -----------------------------
## aaa aab aac aad aae abb abc abd abe acc acd ace
## add ade aee bbb bbc bbd bbe bcc bcd bce bdd bde
## bee ccc ccd cce cdd cde cee ddd dde dee eee
##
## actual words: 35 (m+n-1)!/(n!(m-1)!) words: 35
Although it works, it's somewhat slow as we have to iterate
over the entire Cartesian Product and the filter list(x)==sorted(x)
has got to be expensive (it's slower than the nested loop algorithm).

Is there a better way to get Combinations With Replacement
using itertools?
Jul 14 '08 #1
4 3284
On Jul 14, 1:26*pm, Mensanator <mensana...@aol.comwrote:
## *Combinations with replacement
## *-----------------------------
## *aaa aab aac aad aae abb abc abd abe acc acd ace
## *add ade aee bbb bbc bbd bbe bcc bcd bce bdd bde
## *bee ccc ccd cce cdd cde cee ddd dde dee eee
##
## *actual words: 35 * *(m+n-1)!/(n!(m-1)!) words: 35

Although it works, it's somewhat slow as we have to iterate
over the entire Cartesian Product and the filter list(x)==sorted(x)
has got to be expensive (it's slower than the nested loop algorithm).

Is there a better way to get Combinations With Replacement
using itertools?
There may a technique to start with the combinations without
replacement and then grow the result by repeating elements:

result = set(combinations('abcde', 3))
# transform 'ab ac ad ae bc bd be cd ce de' into 'aab abb aac
acc ...'
for c in combinations('abcde', 2):
# transform 'ab' --'aab abb'
for i in range(2):
result.add(c[:i] + c[i]*1 + c[i:])
for c in combinations('abcde', 1):
for i in range(1):
# 'a' --'aaa'
result.add(c[:i] + c[i]*2 + c[i:])

If you generalize the above, it may solve the problem using itertools
as a starting point.

Alternatively, it's not too hard to transform the pure python version
given in the docs to one that supports combinations with replacement:

def combinations_with_replacement(iterable, r):
pool = tuple(iterable)
n = len(pool)
indices = [0] * r
yield tuple(pool[i] for i in indices)
while 1:
for i in reversed(range(r)):
if indices[i] != n - 1:
break
else:
return
indices[i] += 1
for j in range(i+1, r):
indices[j] = indices[j-1]
yield tuple(pool[i] for i in indices)
Raymond
Jul 15 '08 #2
On Jul 15, 1:44 am, Raymond Hettinger <pyt...@rcn.comwrote:
On Jul 14, 1:26 pm, Mensanator <mensana...@aol.comwrote:
## Combinations with replacement
## -----------------------------
## aaa aab aac aad aae abb abc abd abe acc acd ace
## add ade aee bbb bbc bbd bbe bcc bcd bce bdd bde
## bee ccc ccd cce cdd cde cee ddd dde dee eee
##
## actual words: 35 (m+n-1)!/(n!(m-1)!) words: 35
Although it works, it's somewhat slow as we have to iterate
over the entire Cartesian Product and the filter list(x)==sorted(x)
has got to be expensive (it's slower than the nested loop algorithm).
Is there a better way to get Combinations With Replacement
using itertools?

There may a technique to start with the combinations without
replacement and then grow the result by repeating elements:
Great idea, I had only considered making a sub=set. It never
occured to me to try and make a super=set.

Thanks for the suggestions, they've given me some
ideas to try.
>
result = set(combinations('abcde', 3))
# transform 'ab ac ad ae bc bd be cd ce de' into 'aab abb aac
acc ...'
for c in combinations('abcde', 2):
# transform 'ab' --'aab abb'
for i in range(2):
result.add(c[:i] + c[i]*1 + c[i:])
for c in combinations('abcde', 1):
for i in range(1):
# 'a' --'aaa'
result.add(c[:i] + c[i]*2 + c[i:])

If you generalize the above, it may solve the problem using itertools
as a starting point.

Alternatively, it's not too hard to transform the pure python version
given in the docs to one that supports combinations with replacement:
I was trying to avoid that kind of solution.

ifilter(product()) is exactly the kind of thing
I'm looking for, just wondering if there's a
better way, using a different combination of
functions.
>
def combinations_with_replacement(iterable, r):
pool = tuple(iterable)
n = len(pool)
indices = [0] * r
yield tuple(pool[i] for i in indices)
while 1:
for i in reversed(range(r)):
if indices[i] != n - 1:
break
else:
return
indices[i] += 1
for j in range(i+1, r):
indices[j] = indices[j-1]
yield tuple(pool[i] for i in indices)

Raymond
Jul 16 '08 #3
On Jul 16, 7:20*am, Mensanator <mensana...@aol.comwrote:
## *Combinations with replacement
## *-----------------------------
## *aaa aab aac aad aae abb abc abd abe acc acd ace
## *add ade aee bbb bbc bbd bbe bcc bcd bce bdd bde
## *bee ccc ccd cce cdd cde cee ddd dde dee eee
##
## *actual words: 35 * *(m+n-1)!/(n!(m-1)!) words: 35
>>for x in combinations(range(7), 4):
... x = [-1] + list(x) + [7]
... print ''.join(c*(x[i+1]-x[i]-1) for i, c in
enumerate('abcde'))
...
eee
dee
dde
ddd
cee
cde
cdd
cce
ccd
ccc
bee
bde
bdd
bce
bcd
bcc
bbe
bbd
bbc
bbb
aee
ade
add
ace
acd
acc
abe
abd
abc
abb
aae
aad
aac
aab
aaa
Generalization left as an exercise for the reader.

Mark
Jul 16 '08 #4
On Jul 16, 5:05 am, Mark Dickinson <dicki...@gmail.comwrote:
On Jul 16, 7:20 am, Mensanator <mensana...@aol.comwrote:
## Combinations with replacement
## -----------------------------
## aaa aab aac aad aae abb abc abd abe acc acd ace
## add ade aee bbb bbc bbd bbe bcc bcd bce bdd bde
## bee ccc ccd cce cdd cde cee ddd dde dee eee
##
## actual words: 35 (m+n-1)!/(n!(m-1)!) words: 35
>for x in combinations(range(7), 4):
... x = [-1] + list(x) + [7]
... print ''.join(c*(x[i+1]-x[i]-1) for i, c in enumerate('abcde'))
<snip printout>
>
Generalization left as an exercise for the reader.
First part of exercise: figure out what's going on.

##[-1, 0, 1, 2, 3, 7] ['', '', '', '', 'eee'] eee
##[-1, 0, 1, 2, 4, 7] ['', '', '', 'd', 'ee'] dee
##[-1, 0, 1, 2, 5, 7] ['', '', '', 'dd', 'e'] dde
##[-1, 0, 1, 2, 6, 7] ['', '', '', 'ddd', ''] ddd
##[-1, 0, 1, 3, 4, 7] ['', '', 'c', '', 'ee'] cee
##[-1, 0, 1, 3, 5, 7] ['', '', 'c', 'd', 'e'] cde
##[-1, 0, 1, 3, 6, 7] ['', '', 'c', 'dd', ''] cdd
##[-1, 0, 1, 4, 5, 7] ['', '', 'cc', '', 'e'] cce
##[-1, 0, 1, 4, 6, 7] ['', '', 'cc', 'd', ''] ccd
##[-1, 0, 1, 5, 6, 7] ['', '', 'ccc', '', ''] ccc
## Damn, that's clever
## empty strings disappear when joined

Here's what I came with for a generalization.
s = 'abcde'
m = len(s)
n = 3
mn1 = m+n-1
m1 = m-1

p = [tuple(''.join(c*(q[i+1]-q[i]-1) for i, c in enumerate(s))) \
for q in [[t for t in chain.from_iterable(([-1],r,[mn1]))] \
for r in combinations(range(mn1), m1)]]

I used the tuple() to give output consistent with the itertools
functions.

Combinations with replacement
[26 letters 4 at a time]
version 2 (Mark Dickinson)
-------------------------------------------------------
actual words: 23751 (m+n-1)!/(n!(m-1)!) words: 23751
0.828000068665 seconds

Drat, that's not very impressive.

And here I thought using chain.from_iterable was a nice touch.

Not much better than my version.

p = [i for i in ifilter(lambda x:
list(x)==sorted(x),product(s,repeat=n))]

Combinations with replacement
[26 letters 4 at a time]
(using ifilter(product))
-------------------------------------------------------
actual words: 23751 (m+n-1)!/(n!(m-1)!) words: 23751
0.84299993515 seconds

Maybe all the time saved not iterating through the entire
Cartesian Product is lost to the overhead of all that list
and string manipulation. Makes me wish they had done this
function directly in itertools.

Even the full Cartesian Product is faster despite being
almost 20 times larger:

Permutations with replacement
[26 letters 4 at a time]
(using product)
-------------------------------------------------------
0.453000068665 seconds for 456976 words

Not to mention my goofy ooloop6 program (which certainly
isn't a replacement for itertools since it only works with
a single sorted iterable).

Combinations with replacement
[26 letters 4 at a time]
original nested for loop
-------------------------------------------------------
0.18700003624 seconds for 23751 words

Permutations with replacement
[26 letters 4 at a time]
original nested for loop
-------------------------------------------------------
0.344000101089 seconds for 456976 words

So, maybe there simply ISN'T a GOOD way to do Combinations
With Replacement.

Thanks anyway.
>
Mark
Jul 19 '08 #5

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

10
by: Jeremy Fincher | last post by:
Sometimes I find myself simply wanting the length of an iterator. For example, to collect some (somewhat useless ;)) statistics about a program of mine, I've got code like this: objs =...
6
by: Robert Brewer | last post by:
def warehouse(stock, factory=None): """warehouse(stock, factory=None) -> iavailable, iremainder. Iterate over stock, yielding each value. Once the 'stock' sequence is exhausted, the factory...
18
by: Ville Vainio | last post by:
For quick-and-dirty stuff, it's often convenient to flatten a sequence (which perl does, surprise surprise, by default): ]]] -> One such implementation is at ...
0
by: Steven Bethard | last post by:
gene.tani@gmail.com wrote: > window / cons / fencepost / slice functions: +1 > > (with a flag to say if you want to truncate or pad incomplete tuples > at end of input sequence. > >...
21
by: Steven Bethard | last post by:
Jack Diederich wrote: > > itertools to iter transition, huh? I slipped that one in, I mentioned > it to Raymond at PyCon and he didn't flinch. It would be nice not to > have to sprinkle 'import...
41
by: rurpy | last post by:
The code below should be pretty self-explanatory. I want to read two files in parallel, so that I can print corresponding lines from each, side by side. itertools.izip() seems the obvious way to...
23
by: Mathias Panzenboeck | last post by:
I wrote a few functions which IMHO are missing in python(s itertools). You can download them here: http://sourceforge.net/project/showfiles.php?group_id=165721&package_id=212104 A short...
13
by: 7stud | last post by:
Bejeezus. The description of groupby in the docs is a poster child for why the docs need user comments. Can someone explain to me in what sense the name 'uniquekeys' is used this example: ...
17
by: Raymond Hettinger | last post by:
I'm considering deprecating these two functions and would like some feedback from the community or from people who have a background in functional programming. * I'm concerned that use cases for...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.