Последовательно выбирать части строки, похожие на ngram - PullRequest
1 голос
/ 30 мая 2020

Вот проблема, которую я пытаюсь решить.

Например, есть эта строка

my_string = 'jan feb mar'

И я хочу, чтобы такие элементы последовательно создавались в списке. Всегда верно, что слова в строке разделяются с помощью ' '.

my_function(my_string)
output = ['jan', 'jan feb', 'jan mar', 'jan feb mar', 'feb','feb mar','mar']

То, что я пробовал, находится ниже, и это не то, что я хочу.

my_string = "jan feb mar"
words_list = my_string.split(' ')
words = [' '.join(words_list[i:i+n]) for i in range(len(words_list) - n+1)]
words.extend(input_list)

Пожалуйста, помогите я здесь. Спасибо.

Ответы [ 5 ]

2 голосов
/ 30 мая 2020

Хороший способ подумать об этих комбинациях - это счет в двоичном формате. Имея список вроде ['jan', 'feb', 'mar'], вы можете думать, что каждый из ваших выборов замаскирован двоичным числом. Например, 110 будет соответствовать jan feb. Поскольку вы ищете все комбинации, вы можете просто сосчитать от 1 до количества комбинаций и использовать двоичное число, чтобы замаскировать выбор. Это дает очень емкое решение:

words  = 'jan feb mar'.split()

def all_sets(words):
    l = len(words)
    for n in range(1, 2**l):
        binstring = format(n, f'0{l}b')[::-1]
        yield " ".join([word for flag, word in zip(binstring, words) if int(flag)])

list(all_sets(words))
# ['jan', 'feb', 'jan feb', 'mar', 'jan mar', 'feb mar', 'jan feb mar']
1 голос
/ 30 мая 2020

То, что вы хотите, это все combinations всех размеров (1, 2 и 3), комбинации сохраняют порядок (перестановки делают комбинацию в каждом порядке)

from itertools import combinations
print(list(combinations(my_string.split(' '), r=1))) # [('jan',), ('feb',), ('mar',)]
print(list(combinations(my_string.split(' '), r=2))) # [('jan', 'feb'), ('jan', 'mar'), ('feb', 'mar')]
print(list(combinations(my_string.split(' '), r=3))) # [('jan', 'feb', 'mar')]

Теперь вам нужно выполняйте их автоматически, поэтому l oop по количеству элементов во входных данных и объединение каждого слова

from itertools import combinations, chain

# pythonic way
def my_function(values):
    items = my_string.split(" ")
    return list(chain([' '.join(c) for i in range(1,1+len(items)) for c in combinations(items, r=i)]))

# loop way
def my_function(values):
    items = my_string.split(" ")
    result = []
    for i in range(1,1+len(items)):
      comb = combinations(items, r=i)
      result.extend(' '.join(c) for c in comb)
    return result
  • chain сводит список списка в один список

CODE DEMO

1 голос
/ 30 мая 2020

Как насчет этого? Просто создайте поиск для сортировки

import itertools 

def my_function(my_string):
    def subsets(s): 
      output = []
      for i in range(1,len(s)+1):
        output +=  list(itertools.combinations(s, i))
      return output



    my_list = my_string.split()
    my_order = {val:ind for ind,val in enumerate(my_list)}
    print(my_order)
    output =  subsets(my_list)
    output = [' '.join(sorted(list(i), key=my_order.get)) for i in output]
    return output
my_string = 'jan feb mar' 
output = my_function(my_string)

print(output)
0 голосов
/ 30 мая 2020

Путь Марка , на мой взгляд, лучший, но вот еще один вариант для хорошей меры. Это работает с обычными комбинациями алгоритма любой длины с вложенным l oop результатов, чтобы реорганизовать вывод в соответствии с SP c OP. Я возвращаю генератор, но, к сожалению, большая часть работы выполняется заранее.

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

import itertools

def all_combs(L):
    combinations = [list(itertools.combinations(L, i + 1)) for i in range(len(L))]

    for i in range(len(L)):
        for j in range(len(combinations) - i):
            for comb in combinations[j][i+i*j:i+j+1]:
                yield comb

if __name__ == "__main__":
    print(list(map(" ".join, all_combs("jan feb mar".split()))))

Вывод:

['jan', 'jan feb', 'jan mar', 'jan feb mar', 'feb', 'feb mar', 'mar']
0 голосов
/ 30 мая 2020

используя permutations

from itertools import permutations as per
res = []
my_string = 'jan feb mar'
l = my_string.split()
for i in range(len(l)):
    res.extend(list(per(l, i+1)))

res = [' '.join(i) for i in res]
print(res)

вывод

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