Как создать 5-символьные комбинации строк (1 цифра, две одинаковые буквы и две разные равные буквы) без дублирования - PullRequest
0 голосов
/ 07 сентября 2018

Я пытаюсь сгенерировать комбинации из 5-символьных строк, состоящих из четырех букв (ровно две равны, а две повторяющиеся равны) и одной цифры.

Пример для ПРАВИЛЬНЫЕ комбинации:

1aabb  
b1aab  
ca3ac  

Пример для НЕПРАВИЛЬНЫХ комбинаций:

1aaaa  -> incorrect because there are more than 2 equal letters
1aaab  -> Same as the previous
1abcd  -> No 2 equal letters + 2 equal different letters  

Это код, который я использую:

from itertools import combinations, permutations, product

LETTERS = 'bcdfghjklmnpqrstvwxz'
DIGITS = '2456789'

def aabb1(letters=LETTERS, digits=DIGITS):
    """Generate the distinct 5-character strings consisting of four
    letters (exactly two are equal and another repeat two are equal) and one digit.

    """
    combs = []
    for (a, b), (i, j), (x, y), d, k in product(
            permutations(letters, 2),   # Two letters (a repeated).
            combinations(range(4), 2),  # Positions for the repeated letter.
            combinations(range(2), 2),  # Positions for the second repeated letter.
            digits,                     # One digit.
            range(5)):                  # Positions for the digit.
        result = []
        result[i:i] = a,
        result[j:j] = a,
        result[x:x] = b,
        result[y:y] = b,
        result[k:k] = d,
        combs.append(''.join(result))

    print(len(combs))
    return combs

Это печатает, что у меня есть 79 800 комбинаций, но это неправильно, потому что я считаю дублированные комбинации:
enter image description here

Проблема в том, что он выбирает какую-то букву, например, a, чтобы появиться дважды, а затем повторную букву, например, f, чтобы появиться дважды, чтобы мы получили что-то вроде: a3faf, но позже он выбирает первая буква как f и вторая как a и получение снова a3faf.
В математике я могу решить это с делением на 2:

enter image description here

Но не уверен, как это сделать правильно в моем коде.

Можете ли вы предложить, как я могу предотвратить это в моем коде? Смысл, получить комбинации без дублирования.

Ответы [ 3 ]

0 голосов
/ 07 сентября 2018

Измените permutations(letters, 2) на combinations(letters, 2).permutations() доставит ('a', 'b') и ('b', 'a'), но combinations() доставит ('a', 'b').Ваши комбинации для буквенных позиций заботятся обо всех порядках этих букв, поэтому вам не нужно видеть их дважды.

Редактировать: В дополнение к предыдущему исправлению, вычисление позицийвторая буква, основанная на первой букве, наконец исправляет это.Поэтому, если 'a' имеет индекс 0 и 2, тогда 'b' должен быть с индексом 1 и 4.

def aabb1(letters=LETTERS, digits=DIGITS):
    """Generate the distinct 5-character strings consisting of four
    letters (exactly two are equal and another repeat two are equal) and one digit.

    """
    letterdxs = set(range(4))
    combs = []
    for (a, b), (i, j), d, k in product(
            combinations(letters, 2),   # Two letters (a repeated).
            combinations(range(4), 2),  # Positions for the 1st repeated letter.
            digits,                     # One digit.
            range(5)):                  # Positions for the digit.
        x, y = letterdxs.difference((i, j))
        result = []
        result[i:i] = a,
        result[j:j] = a,
        result[x:x] = b,
        result[y:y] = b,
        result[k:k] = d,
        combs.append(''.join(result))
    print(len(combs))
    return combs
0 голосов
/ 07 сентября 2018

Для фиксированной длины и формата этот простой код генерирует 39900 комбинаций:

LETTERS = 'bcdfghjklmnpqrstvwxz'
DIGITS = '2456789'

def insdig(s, d):
    for i in range(5):
        ss = s[:i] + d + s[i:]
        print(ss)

def aabb1():
    for dig in DIGITS:
        for i in range(len(LETTERS)-1):
            for j in range(i+1, len(LETTERS)):
                a = LETTERS[i]
                b = LETTERS[j]
                insdig(a+a+b+b, dig)
                insdig(a+b+a+b, dig)
                insdig(b+a+a+b, dig)
                insdig(a+b+b+a, dig)
                insdig(b+a+b+a, dig)
                insdig(b+b+a+a, dig)

aabb1()
0 голосов
/ 07 сентября 2018

Вы можете написать рекурсивную функцию:

#1aabb  
#b1aab  
#ca3ac  
from collections import Counter
LETTERS = 'bcdfghjklmnpqrstvwxz'
DIGITS = '2456789'
def combinations(d, current = []):
   if len(current) == 5:
      yield ''.join(current)
   else:
      for i in d:
        _d = Counter(current)
        if i.isdigit() and not any(c.isdigit() for c in current):
          yield from combinations(d, current+[i])
        elif (not current or _d.get(i, 0) == 1 or sum(c.isalpha() for c in current) < 2) and i.isalpha():
          yield from combinations(d, current+[i])

result = list(combinations(LETTERS+DIGITS))

Вывод (первые 100 результатов):

['bcbc2', 'bcbc4', 'bcbc5', 'bcbc6', 'bcbc7', 'bcbc8', 'bcbc9', 'bcb2c', 'bcb4c', 'bcb5c', 'bcb6c', 'bcb7c', 'bcb8c', 'bcb9c', 'bccb2', 'bccb4', 'bccb5', 'bccb6', 'bccb7', 'bccb8', 'bccb9', 'bcc2b', 'bcc4b', 'bcc5b', 'bcc6b', 'bcc7b', 'bcc8b', 'bcc9b', 'bc2bc', 'bc2cb', 'bc4bc', 'bc4cb', 'bc5bc', 'bc5cb', 'bc6bc', 'bc6cb', 'bc7bc', 'bc7cb', 'bc8bc', 'bc8cb', 'bc9bc', 'bc9cb', 'bdbd2', 'bdbd4', 'bdbd5', 'bdbd6', 'bdbd7', 'bdbd8', 'bdbd9', 'bdb2d', 'bdb4d', 'bdb5d', 'bdb6d', 'bdb7d', 'bdb8d', 'bdb9d', 'bddb2', 'bddb4', 'bddb5', 'bddb6', 'bddb7', 'bddb8', 'bddb9', 'bdd2b', 'bdd4b', 'bdd5b', 'bdd6b', 'bdd7b', 'bdd8b', 'bdd9b', 'bd2bd', 'bd2db', 'bd4bd', 'bd4db', 'bd5bd', 'bd5db', 'bd6bd', 'bd6db', 'bd7bd', 'bd7db', 'bd8bd', 'bd8db', 'bd9bd', 'bd9db', 'bfbf2', 'bfbf4', 'bfbf5', 'bfbf6', 'bfbf7', 'bfbf8', 'bfbf9', 'bfb2f', 'bfb4f', 'bfb5f', 'bfb6f', 'bfb7f', 'bfb8f', 'bfb9f', 'bffb2', 'bffb4']
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...