Вопрос

Мне нужно иметь возможность написать функцию, которая показывает повторяющиеся слова из строки и возвращает список строк в порядке их появления и игнорирует небуквы.

например, при подсказке об объятиях

repetitions :: String -> [String]

repetitions > "My bag is is action packed packed."
output> ["is","packed"]
repetitions > "My name  name name is Sean ."
output> ["name","name"]
repetitions > "Ade is into into technical drawing drawing ."
output> ["into","drawing"]
Это было полезно?

Решение

Чтобы разделить строку на слова, используйте команду words функция (в Prelude).Чтобы исключить символы, не являющиеся словами, filter с Data.Char.isAlphaNum.Свяжите список вместе с его хвостом, чтобы получить соседние пары. (x, y).Сверните список, создав новый список, содержащий все x где x == y.

Что-то вроде:

repetitions s = map fst . filter (uncurry (==)) . zip l $ tail l
  where l = map (filter isAlphaNum) (words s)

Я не уверен, что это работает, но это должно дать вам примерное представление.

Другие советы

Я новичок в этом языке, поэтому мое решение может показаться уродливым в глазах ветерана Haskell, но в любом случае:

let repetitions x = concat (map tail (filter (\x -> (length x) > 1) (List.group (words (filter (\c -> (c >= 'a' && c <= 'z') || (c>='A' && c <= 'Z') ||  c==' ') x)))))

Эта часть удалит из строки все, кроме букв и пробелов. с:

filter (\c -> (c >= 'a' && c <= 'z') || (c>='A' && c <= 'Z') ||  c==' ') s

Этот разделит строку с к словам и группировать одни и те же слова в списки, возвращая список списков:

List.group (words s)

Когда эта часть удалит все списки, содержащие менее двух элементов:

filter (\x -> (length x) > 1) s

После чего мы объединим все списки в один, удалив из них один элемент.

concat (map tail s)

Это может быть неэлегантно, однако концептуально очень просто.Я предполагаю, что он ищет последовательные повторяющиеся слова, как в примерах.

-- a wrapper that allows you to give the input as a String
repititions :: String -> [String]
repititions s = repititionsLogic (words s)
-- dose the real work 
repititionsLogic :: [String] -> [String]
repititionsLogic [] = []
repititionsLogic [a] = []
repititionsLogic (a:as) 
    | ((==) a (head as)) = a : repititionsLogic as
    | otherwise = repititionsLogic as

Основываясь на том, что ответил Александр Прокофьев:

repetitions x = concat (map tail (filter (\x -> (length x) > 1) (List.group (word (filter (\c -> (c >= 'a' && c <= 'z') || (c>='A' && c <= 'Z') || c==' ') x)))))

Удалите ненужную скобку:

repetitions x = concat (map tail (filter (\x -> length x > 1) (List.group (word (filter (\c -> c >= 'a' && c <= 'z' || c>='A' && c <= 'Z' || c==' ') x)))))

Используйте $, чтобы удалить дополнительные круглые скобки (каждый $ может заменить открывающую скобку, если конечная скобка находится в конце выражения):

repetitions x = concat $ map tail $ filter (\x -> length x > 1) $ List.group $ word $ filter (\c -> c >= 'a' && c <= 'z' || c>='A' && c <= 'Z' || c==' ') x

Замените диапазоны символов функциями из Data.Char, объедините concat и карту:

repetitions x = concatMap tail $ filter (\x -> length x > 1) $ List.group $ word $ filter (\c -> isAlpha c || isSeparator c) x

Используйте разделы и каррирование в стиле без точек для упрощения. (\x -> length x > 1) to ((>1) . length).Это сочетает в себе length с (>1) (частично применяемый оператор или раздел) в конвейере справа налево.

repetitions x = concatMap tail $ filter ((>1) . length) $ List.group $ word $ filter (\c -> isAlpha c || isSeparator c) x

Устраните явную переменную «x», чтобы сделать общее выражение свободным от точек:

repetitions = concatMap tail . filter ((>1) . length) . List.group . word . filter (\c -> isAlpha c || isSeparator c)

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top