Mostra uma lista de palavras repetidas em haskell
Pergunta
Eu preciso ser capaz de escrever uma função que mostra repetiu as palavras de uma string e retornar uma lista de strings em ordem de sua ocorrência e ignorar os não-letras
por exemplo em abraços rápida
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"]
Solução
Para dividir uma string em palavras, usar a função words
(no Prelude).
Para eliminar caracteres não-palavra, filter
com Data.Char.isAlphaNum
.
Zip da lista, juntamente com sua cauda para obter pares adjacentes (x, y)
.
Dobre a lista, consing uma nova lista que contém todos x
onde x
== y
.
Someting como:
repetitions s = map fst . filter (uncurry (==)) . zip l $ tail l
where l = map (filter isAlphaNum) (words s)
Eu não tenho certeza que as obras, mas deve dar uma idéia aproximada.
Outras dicas
Eu sou novo a esta linguagem de modo a minha solução poderia ser um tipo de feio nos olhos de um veterano Haskell, mas de qualquer maneira:
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)))))
Esta parte irá remover todas as letras não e não espaços de uma string s :
filter (\c -> (c >= 'a' && c <= 'z') || (c>='A' && c <= 'Z') || c==' ') s
Este irá dividir uma string s para palavras e grupo as mesmas palavras para listas lista de listas de retorno:
List.group (words s)
Quando esta parte irá remover todas as listas com menos de dois elementos:
filter (\x -> (length x) > 1) s
Depois do que vamos concatenar todas as listas para uma remoção de um elemento com eles embora
concat (map tail s)
Isso pode ser inelegent, no entanto, é conceitualmente muito simples. Estou assumindo que a sua procura de palavras duplicadas consecutivas como exemplos.
-- 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
Com base no que Alexander Prokofyev respondeu:
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)))))
Remova parênteses desnecessários:
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)))))
Use $ para remover mais parêntese (cada $ pode substituir um parêntese de abertura se o parêntese final é no final da expressão):
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
Substituir intervalos de caracteres com funções de Data.Char, concat merge e mapa de:
repetitions x = concatMap tail $ filter (\x -> length x > 1) $ List.group $ word $ filter (\c -> isAlpha c || isSeparator c) x
Use uma seção e currying em grande estilo pontos-livres para (\x -> length x > 1) to ((>1) . length)
simplificar. Isto combina com length
(> 1) (um operador parcialmente aplicada, ou secção ) numa tubagem da direita para a esquerda.
repetitions x = concatMap tail $ filter ((>1) . length) $ List.group $ word $ filter (\c -> isAlpha c || isSeparator c) x
Elimine explícita variável "x" para fazer pontos-livres expressão geral:
repetitions = concatMap tail . filter ((>1) . length) . List.group . word . filter (\c -> isAlpha c || isSeparator c)
Agora, toda a função, a leitura da direita para a esquerda, é um gasoduto que filtra apenas alfa ou um separador de caracteres, divide-lo em palavras, quebra-lo em grupos, filtra esses grupos com mais de 1 elemento, e depois reduz os restantes grupos para o primeiro elemento de cada um.