Generating a list of repetitions regardless of the order

寵の児 提交于 2019-12-05 08:50:50

I would start by making the following observations:

  1. The first element of each combination must be 0.
  2. The second element must be 0 or 1.
  3. The third element must be 0, 1 or 2, but it can only be 2 if the second element was 1.

These observations suggest the following algorithm:

def assignments(n, m, used=0):
    """Generate assignments of `n` items to `m` indistinguishable
    buckets, where `used` buckets have been used so far.

        >>> list(assignments(3, 1))
        [(0, 0, 0)]
        >>> list(assignments(3, 2))
        [(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1)]
        >>> list(assignments(3, 3))
        [(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (0, 1, 2)]

    """
    if n == 0:
        yield ()
        return
    aa = list(assignments(n - 1, m, used))
    for first in range(used):
        for a in aa:
            yield (first,) + a
    if used < m:
        for a in assignments(n - 1, m, used + 1):
            yield (used,) + a

This handles your use case (12 items, 5 buckets) in a few seconds:

>>> from timeit import timeit
>>> timeit(lambda:list(assignments(12, 5)), number=1)
4.513746023178101
>>> sum(1 for _ in assignments(12, 5))
2079475

This is substantially faster than the function you give at the end of your answer (the one that calls product and then drops the invalid assignments) would be if it were modified to handle the (12, 5) use case:

>>> timeit(lambda:list(test(12, 5)), number=1)
540.693009853363
fuesika

Before checking for duplicates, you should harmonize the notation (assuming you don't want to set up some fancy AI): iterate through the lists and assign set-affiliation numbers for differing elements starting at 0, counting upwards. That is, you create a temporary dictionary per line that you are processing.

An exemplary output would be

(0,0,0) -> (0,0,0)
(0,1,0) -> (0,1,0)

but

(1,0,1) -> (0,1,0)

Removing the duplicates can then easily be performed as the problem is reduced to the problem of the solved question at Python : How to remove duplicate lists in a list of list?

If you only consider the elements of the cartesian product where the first occurrences of all indices are sorted and consecutive from zero, that should be sufficient. itertools.combinations_with_replacement() will eliminate those that are not sorted, so you'll only need to check that indices aren't being skipped.

In your specific case you could simply take the first or the second half of the list of those items produced by a cartesian product.

import itertools

alphabet = '01' 
words3Lettered = [''.join(letter) for letter in itertools.product(alphabet,repeat=3)] 

for n lettered words use repeat=n

words3Lettered looks like this:

['000', '001', '010', '011', '100', '101', '110', '111']

next,

usefulWords = words3Lettered[:len(words3Lettered)/2]

which looks like this:

['000', '001', '010', '011']

you might be interested in the other half i.e. words3Lettered[len(words3Lettered)/2:] though the other half was supposed to "fold" onto the first half.

most probably you want to use the combination of letters in numeric form so...

indexes = [tuple(int(j) for j in word) for word in usefulWords]

which gives us:

[(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1)]
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!