您有一个包含N个元素的列表 您只想打印不是同一列表中其他元素的循环元素的元素
要检查两个字符串是否是彼此的循环排列,我这样做,这很好用:
string1 = "abc"
string2 = "cab"
stringconc = string1 ++ string1
if string2 `isInfixOf` stringconc
then -- it's a circular permuation
else -- it's not
编辑:正如一条评论指出的那样,此测试仅适用于相同大小的字符串
回到真实用例:
checkClean :: [String] -> [String] -> IO String
checkClean [] list = return ""
checkClean (x:xs) list = do
let sequence = cleanInfix x list
if sequence /= "abortmath"
then putStr sequence
else return ()
checkClean xs list
cleanInfix:
cleanInfix :: String -> [String] -> String
cleanInfix seq [] = seq
cleanInfix seq (x:xs) = do
let seqconc = x ++ x
if seq `isInfixOf` seqconc && seq /= x
then "abortmath"
else cleanInfix seq xs
然而,这只是输出......没有 通过一些研究,我发现checkClean中的序列始终是“abortmath” 此外,我对这种“旗帜”流产感到不太满意,因为如果列表中的一个元素是“abortmath”,那么很好......
例如: 如果我有一个由以下内容组成的清单:
NUUNNFFUF
FFUFNUUNN
我应该写 NUUNNFFUF
答案 0 :(得分:0)
你可以用钢笔和纸张制作奇迹......
所以,如果有人对此感兴趣,我是如何解决它的,它可能已经被严格优化但至少它可以工作(我只是想学习haskell,所以它现在已经足够好了)
-- cleanInfix function
cleanInfix :: String -> [String] -> [String] -> [String]
cleanInfix sequence [] cleanlist = cleanlist
cleanInfix sequence (x:xs) cleanlist = do
-- this is where I check for the circular permuation
let sequenceconc = x ++ x
if sequence `isInfixOf` sequenceconc
then cleanInfix sequence xs (delete x cleanlist)
else cleanInfix sequence xs cleanlist
-- checkClean Function
checkClean :: [String] -> [String] -> [String] -> [String]
checkClean [] listesend cleanlist = cleanlist
checkClean (x:xs) listesend cleanlist = do
-- The first delete is to avoid checking if an element is the circular permuation of... itself, because it obviously is... in some way
let liste2 = cleanInfix x (delete x listesend) cleanlist
checkClean xs (delete x listesend) liste2
-- Clean function, first second and third are the command line argument don't worry about them
clean first second third = do
-- create of the result list by asking user for input
let printlist = checkClean result result result -- yes, it's the same list, three times
print printlist -- print the list
答案 1 :(得分:0)
我猜你用这样的东西调用你的初始代码(问题):
result = ["NUUNNFFUF", "FFUFNUUNN"]
main = do
checkClean result result
它不会打印任何内容,因为:
cleanInfix
的第一次调用的参数有以下参数:"NUUNNFFUF"
和["NUUNNFFUF", "FFUFNUUNN"]
cleanInfix
中,因为seq == x
您使用以下参数进行递归调用:"NUUNNFFUF"
和["FFUFNUUNN"]
"NUUNNFFUF"
是"FFUFNUUNN"
的真实排列:cleanInfix
返回"abortmath"
,checkClean
返回()
checkClean
:"FFUFNUUNN"
和["NUUNNFFUF", "FFUFNUUNN"]
"FFUFNUUNN"
是"NUUNNFFUF"
的真实排列:cleanInfix
返回"abortmath"
,checkClean
返回()
基本上,x是y的排列,y是x的排列,因此x和y被丢弃。
你的答案有效,但它非常复杂。
我不会尝试改进您的任何代码,但我会做一般性评论:您应该(您真的应该)避免在您不需要时返回monad:in问题,checkClean
只需要从列表中删除重复项(或“循环重复项”)。这完全是功能性的:您拥有所需的所有信息。因此,请删除do
,let
和return
s!
现在,让我们试着关注这个:
您有一个包含N个元素的列表您只想打印不是同一列表中其他元素的循环元素的元素
为什么不使用关于循环排列的初步知识?
isCircPermOf x y = x `isInfixOf` (y ++ y)
现在,您需要一个接受序列和序列列表的函数,并且只返回第二个元素不是第一个的循环排列:
filterCircDuplicates :: String -> [String] -> [String]
filterCircDuplicates seq [] = []
filterCircDuplicates seq (x:xs) =
if seq `isCircPermOf` x
then removeCircDuplicates seq xs
else x:removeCircDuplicates seq xs
这种模式众所周知,您可以使用filter
来简化它:
filterCircDuplicates seq l = filter (\x -> !seq `isCircPermOf` x) l
或更好:
filterCircDuplicates seq = filter (not.isCircPermOf seq)
请注意签名:not.isCircPermOf seq :: String -> Boolean
。如果当前元素不是seq
的循环排列,则返回true。 (您不必添加列表参数。)
最后一步:您需要一个获取列表并返回此列表但没有(循环)重复项的函数。
removeCircDuplicates :: [String] -> [String]
removeCircDuplicates [] = []
removeCircDuplicates (x:xs) = x:filterCircDuplicates x (removeCircDuplicates xs)
当你的列表有头部和尾部时,你清理尾部,然后删除尾部第一个元素的副本,并保留第一个元素。
同样,你有一个众所周知的模式,fold
:
removeCircDuplicates = foldr (\x acc -> x:filterCircDuplicates x acc) []
从右到左删除重复项。
如果你想要一个单行:
Prelude Data.List> foldr (\x -> ((:) x).filter(not.(flip isInfixOf (x++x)))) [] ["abcd", "acbd", "cdab", "abdc", "dcab"]
["abcd","acbd","abdc"]