Haskell (反向f反向)有效吗?
很多时候,我看到的功能都在列表的开头,例如:Haskell (反向f反向)有效吗?,haskell,Haskell,很多时候,我看到的功能都在列表的开头,例如: trimHead ('\n':xs) = xs trimHead xs = xs 然后我看到了定义: trimTail = reverse . trimHead . reverse 然后我明白了: trimBoth = trimHead . trimTail 它们是干净的,但是trimTail和trimTail都有效吗?有更好的方法吗?从某种意义上讲,流式传输是不可能的,因为需要对整个列表进行评估,才能得到一个元素。但更好的解决方
trimHead ('\n':xs) = xs
trimHead xs = xs
然后我看到了定义:
trimTail = reverse . trimHead . reverse
然后我明白了:
trimBoth = trimHead . trimTail
它们是干净的,但是
trimTail
和trimTail
都有效吗?有更好的方法吗?从某种意义上讲,流式传输是不可能的,因为需要对整个列表进行评估,才能得到一个元素。但更好的解决方案是困难的,因为您需要评估列表的其余部分,以了解是否要修剪换行符。一种稍微更有效的方法是前瞻是否要修剪换行符,并做出适当的反应:
trimTail, trimHead, trimBoth :: String -> String
trimTail ('\n':xs) | all (=='\n') xs = ""
trimTail (x:xs) = x : trimTail xs
trimHead = dropWhile (=='\n')
trimBoth = trimTail . trimHead
如果要修剪换行符,上面的解决方案只根据需要对字符串进行计算。一个更好的方法是结合知识,即下一个n个字符不被修剪。实现这一点留给读者作为练习
编写trimTail
的更好(更短)方法是(通过rotsor):
通常,尽量避免
反转。通常有更好的方法来解决这个问题。考虑这个替代实现
trimTail2 [] = []
trimTail2 ['\n'] = []
trimTail2 (x:xs) = x : trimTail2 xs
trimBoth2 = trimHead . trimTail2
很容易确认trimTail
和trimTail
要求评估整个列表,而trimTail2
和trimTail2
只评估必要的列表
*Main> head $ trimTail ('h':undefined)
*** Exception: Prelude.undefined
*Main> head $ trimBoth ('h':undefined)
*** Exception: Prelude.undefined
*Main> head $ trimTail2 ('h':undefined)
'h'
*Main> head $ trimBoth2 ('h':undefined)
'h'
这意味着,如果不需要整个结果,则您的版本的效率将降低。假设要评估整个列表(如果您不需要整个列表,为什么要修剪结尾?),它的效率大约是从不可变列表中获得的效率的一半,但它具有相同的渐近复杂性O(n)
新列表至少需要:
您必须找到end:n指针遍历
您必须修改端点,从而修改指向端点的内容,等等:n个现有数据的cons和新指针
相反。三叶草。反向执行此操作大约两倍:
第一个reverse
执行n个指针遍历和n个cons
trimHead
可能执行1个指针遍历
第二个reverse
执行n个指针遍历和n个cons
这值得担心吗?在某些情况下,也许是这样。代码是否太慢,这是不是太多了?在其他国家,也许不是。基准!使用reverse
的实现很好而且易于理解,这一点很重要
在列表解决方案中有一个相当自然的递归步骤,它只计算所消耗的输出量,因此在不知道是否需要整个字符串的情况下,可以保存一些计算
trimHead和trimTail是否有效
它们都需要O(n)时间(与列表大小成正比的时间),因为整个列表必须遍历两次才能执行两次反转
有更好的办法吗
那么,你必须使用列表吗?使用Data.Sequence
可以在固定时间内修改列表的任意一端。如果你被列表困住了,那么看看这里建议的其他解决方案。如果您可以使用序列,那么只需修改fuzzxl的答案即可。好吧,使用all
既可爱又微妙。如果你期望文本在中间有大量的<代码> \n\/COD>字符,这有点坏(连续的新行数中的二次数)-但是这种特殊情况似乎不太可能,并且修复这个问题应该是很容易出现的。回答得好!称渐进较慢的算法为“更高效”并不完全正确!下面是“更好的方法”:顺便说一句:trimTail=foldr步骤[],其中步骤'\n'[]=[];步骤xxs=x:xs
@Rotsor很好。我可以把这一点纳入我的答案中吗?或者你想打开另一个答案。澄清一下:你想在结尾处修剪一行还是尽可能多的换行?您的代码提示第一个,但第二个似乎也是可能的。我的答案是第二种情况,第一种情况用哈马尔的。
*Main> head $ trimTail ('h':undefined)
*** Exception: Prelude.undefined
*Main> head $ trimBoth ('h':undefined)
*** Exception: Prelude.undefined
*Main> head $ trimTail2 ('h':undefined)
'h'
*Main> head $ trimBoth2 ('h':undefined)
'h'