Генерация всех уникальных k-подпоследовательностей - PullRequest
3 голосов
/ 22 октября 2019

Я пытаюсь написать функцию Python (по крайней мере на начальном этапе) для генерации всех подпоследовательностей некоторой длины k (где k> 0). Поскольку мне нужны только уникальные подпоследовательности, я храню как подпоследовательности, так и частичные подпоследовательности в set s. Следующее, адаптированное от коллеги, - лучшее, что я мог придумать. Это кажется ... чрезмерно сложным ... и, как я должен иметь возможность злоупотреблять itertools или рекурсией, чтобы делать то, что я хочу делать. Кто-нибудь может сделать лучше?

from typing import Set, Tuple


def subsequences(string: str, k: int) -> Set[Tuple[str, ...]]:
    if len(string) < k:
        return set()
    start = tuple(string[:k])
    result = {start}
    prev_state = [start]
    curr_state = set()
    for s in string[k:]:
        for p in prev_state:
            for i in range(k):
                new = p[:i] + p[i + 1 :] + (s,)
                curr_state.add(new)
        result.update(curr_state)
        prev_state = list(curr_state)
        curr_state.clear()
    return result

(Для контекста меня интересует введение k-строго кусочно-языковых , эффективно обучаемых подклассов обычных языков, и грамматика может бытьхарактеризуется всеми законными k-подпоследовательностями.

В конечном счете, я также думаю об этом в C ++, где std::make_tuple не так мощен, как Python tuple.)

1 Ответ

2 голосов
/ 22 октября 2019

Требуется набор r комбинаций из n предметов (без замены, <= (n choose r).

Дано

import itertools as it

import more_itertools as mit

Код

Опция 1 - itertools.combinations

set(it.combinations("foo", 2))
# {('f', 'o'), ('o', 'o')}

set(it.combinations("foobar", 3))
# {('b', 'a', 'r'),
#  ('f', 'a', 'r'),
#  ('f', 'b', 'a'),
#  ('f', 'b', 'r'),
#  ('f', 'o', 'a'),
#  ('f', 'o', 'b'),
#  ('f', 'o', 'o'),
#  ('f', 'o', 'r'),
#  ('o', 'a', 'r'),
#  ('o', 'b', 'a'),
#  ('o', 'b', 'r'),
#  ('o', 'o', 'a'),
#  ('o', 'o', 'b'),
#  ('o', 'o', 'r')}

Опция 2 - more_itertools.distinct_combinations

list(mit.distinct_combinations("foo", 2))
# [('f', 'o'), ('o', 'o')]

list(mit.distinct_combinations("foobar", 3))
# [('f', 'o', 'o'),
#  ('f', 'o', 'b'),
#  ('f', 'o', 'a'),
#  ('f', 'o', 'r'),
#  ('f', 'b', 'a'),
#  ('f', 'b', 'r'),
#  ('f', 'a', 'r'),
#  ('o', 'o', 'b'),
#  ('o', 'o', 'a'),
#  ('o', 'o', 'r'),
#  ('o', 'b', 'a'),
#  ('o', 'b', 'r'),
#  ('o', 'a', 'r'),
#  ('b', 'a', 'r')]

Обе опции дают одинаковый (неупорядоченный) вывод, однако:

  • Опция 1 принимает набор всех комбинаций (включая дубликаты)
  • Опция 2 не рассчитывает дубликаты промежуточных звеньев

Установка more_itertools через > pip install more_itertools.

См. Также грубая реализация из itertools.combinations в письменном Python.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...