Создайте два последовательных словосочетания из строки - PullRequest
0 голосов
/ 02 мая 2020

Я провел невероятные часы, пытаясь найти способ использовать itertools для преобразования предложения в список фраз из двух слов.

Я хочу взять это: "быстрая коричневая лиса"

И превратите это в следующее: «быстрый», «быстрый коричневый», «коричневый лис»

Все, что я пробовал, возвращает все - от списков из одного слова до списков из четырех слов, но ничего не возвращается, только пары.

Я пробовал множество различных вариантов использования комбинаций itertools, и я знаю, что это выполнимо, но я просто не могу найти правильную комбинацию и не хочу определять функцию для чего-либо Я знаю выполнимо в две строки кода или меньше. Может кто-нибудь, пожалуйста, помогите мне?

Ответы [ 3 ]

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

@ DarrylG ответ, кажется, путь к go, но вы также можете использовать:

s = "the quick brown fox"
p  = s.split()
ns = [f"{w} {p[n+1]}" for n, w in enumerate(p) if n<len(p)-1 ]
# ['the quick', 'quick brown', 'brown fox']

Демо

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

Попробуйте:

s = "the quick brown fox"
words = s.split()
result = [' '.join(pair) for pair in zip(words, words[1:])]
print(result)

Вывод

['the quick', 'quick brown', 'brown fox']

Пояснение

Создание итератора для пар слов с использованием zip

zip(words, words[1:]

Перебор пар

for pair in zip(words, words[1:])

Создание результирующих слов

[' '.join(pair) for ...]
0 голосов
/ 02 мая 2020

Если вам нужно чистое итераторное решение для больших строк с постоянным использованием памяти:

input       = "the quick brown fox"
input_iter1 = map(lambda m: m.group(0), re.finditer(r"[^\s]+", input))                                                                                                                     
input_iter2 = map(lambda m: m.group(0), re.finditer(r"[^\s]+", input))                                                                                                                     
next(input_iter2) # skip first
output = itertools.starmap(
    lambda a, b: f"{a} {b}", 
    zip(input_iter1, input_iter2)
)
list(output)                                                         
# ['the quick', 'quick brown', 'brown fox']

Если у вас есть дополнительная 3х-строковая память для хранения как split (), так и удвоенного вывода в виде списков, тогда оно может быть быстрее и проще не использовать itertools:

inputs = "the quick brown fox".split(' ')    

output = [ f"{inputs[i]} {inputs[i+1]}" for i in range(len(inputs)-1) ] 
#  ['the quick', 'quick brown', 'brown fox']

Обновление

Обобщенное решение для поддержки произвольных размеров ngram:

from typing import Iterable  
import itertools

def ngrams_iter(input: str, ngram_size: int, token_regex=r"[^\s]+") -> Iterable[str]:
    input_iters = [ 
        map(lambda m: m.group(0), re.finditer(token_regex, input)) 
        for n in range(ngram_size) 
    ]
    # Skip first words
    for n in range(1, ngram_size): list(map(next, input_iters[n:]))  

    output_iter = itertools.starmap( 
        lambda *args: " ".join(args),  
        zip(*input_iters) 
    ) 
    return output_iter

Тест:

input = "If you want a pure iterator solution for large strings with constant memory usage"
list(ngrams_iter(input, 5))

Вывод:

['If you want a pure',
 'you want a pure iterator',
 'want a pure iterator solution',
 'a pure iterator solution for',
 'pure iterator solution for large',
 'iterator solution for large strings',
 'solution for large strings with',
 'for large strings with constant',
 'large strings with constant memory',
 'strings with constant memory usage']

Вы также можете найти этот вопрос актуальным: n-грамм в python, четыре, пять, шесть грамм?

...