Permutations with repetition in Python

后端 未结 5 1287
囚心锁ツ
囚心锁ツ 2021-02-10 03:47

I want to iterate over all the vertices of an n dimensional cube of size 1. I know I could do that with itertools.product as follows:

&         


        
5条回答
  •  时光说笑
    2021-02-10 04:06

    Following is some code that runs faster (for medium n) and several times faster (for large n) than that of Cam or Eevee. A time comparison follows.

    def cornersjc (n):   # Re: jw code
        from itertools import product
        m = (n+1)/2
        k = n-m
        # produce list g of lists of tuples on k bits
        g = [[] for i in range(k+1)]
        for j in product((0,1), repeat=k):
            g[sum(j)].append(tuple(j))
        # produce list h of lists of tuples on m bits
        if k==m:
            h = g
        else:
            h = [[] for i in range(m+1)]
            for j in product((0,1), repeat=m):
                h[sum(j)].append(tuple(j))
        # Now deliver n-tuples in proper order
        for b in range(n+1):  # Deliver tuples with b bits set
            for lb in range(max(0, b-m), min(b+1,k+1)):
                for l in g[lb]:
                    for r in h[b-lb]:
                        yield l+r
    

    The timing results shown below are from a series of %timeit calls in ipython. Each call was of a form like
    %timeit [x for x in cube1s.f(n)]
    with the names cornersjc, cornerscc, cornersec, cornerses in place of f (standing for my code, Cam's code, Eevee's code, and my version of Eevee's method) and a number in place of n.

    n    cornersjc    cornerscc    cornersec    cornerses
    
    5      40.3 us      45.1 us      36.4 us      25.2 us    
    6      51.3 us      85.2 us      77.6 us      46.9 us    
    7      87.8 us      163 us       156 us       88.4 us    
    8     132 us       349 us       327 us       178 us    
    9     250 us       701 us       688 us       376 us    
    10    437 us      1.43 ms      1.45 ms       783 us
    11    873 us      3 ms         3.26 ms      1.63 ms
    12   1.87 ms      6.66 ms      8.34 ms      4.9 ms
    

    Code for cornersjc was given above. Code for cornerscc, cornersec, and cornerses is as follows. These produce the same output as cornersjc, except that Cam's code produces a list of lists instead of a list of tuples, and within each bit-count group produces in reverse.

    def cornerscc(n):   # Re: Cam's code
        from itertools import combinations
        for number_of_ones in xrange(0, n + 1):
            for location_of_ones in combinations(xrange(0, n), number_of_ones):
                result = [0] * n
                for location in location_of_ones:
                    result[location] = 1
                yield result
    
    def cornersec (n):   # Re:  Eevee's code
        from itertools import product
        vertices = ((v.count(1), v)
                    for v in product((0, 1), repeat=n))
        for count, vertex in sorted(vertices):
            yield vertex
    
    def cornerses (n):   # jw mod. of Eevee's code
        from itertools import product
        for vertex in sorted(product((0, 1), repeat=n), key=sum):
            yield vertex
    

    Note, the last three lines of cornersjc can be replaced by

                for v in product(g[lb], h[b-lb]):
                    yield v[0]+v[1]
    

    which is cleaner but slower. Note, if yield v is used instead of yield v[0]+v[1], the code runs faster than cornersjc but (at n=5) produces pair-of-tuple results like ((1, 0), (1, 1, 0)); when yield v[0]+v[1] is used, the code runs slower than cornersjc but produces identical results, a list of tuples like (1, 0, 1, 1, 0). An example timing follows, with cornersjp being the modified cornersjc.

    In [93]: for n in range(5,13):
        %timeit [x for x in cube1s.cornersjp(n)]
       ....:     
    10000 loops, best of 3: 49.3 us per loop
    10000 loops, best of 3: 64.9 us per loop
    10000 loops, best of 3: 117 us per loop
    10000 loops, best of 3: 178 us per loop
    1000 loops, best of 3: 351 us per loop
    1000 loops, best of 3: 606 us per loop
    1000 loops, best of 3: 1.28 ms per loop
    100 loops, best of 3: 2.74 ms per loop
    

提交回复
热议问题