简短版本:
我想对列表进行排序,然后对该排序列表执行操作,过滤/提取数据以形成新列表,所有操作都在一个函数中。
长版:
我正在使用these lessons教自己Haskell。我目前正在Homework 2练习5。
我需要编写一个函数whatWentWrong
,它接受一个未排序的 LogMessages列表并返回一个字符串列表。字符串是LogMessages的String部分,它是用Error构造的,其中Error代码是> 50.它们应该按LogMessage的TimeStamp部分排序。
我为whatWentWrong
编写了一个可行的函数,但它确实很慢(你会明白为什么)。
whatWentWrong :: [LogMessage] -> [String]
whatWentWrong [] = []
whatWentWrong ys@((LogMessage (Error code) _ msg):xs)
| ys /= inOrder (build ys)
= whatWentWrong (inOrder (build ys))
| code > 50
= [msg] ++ whatWentWrong xs
| otherwise
= whatWentWrong xs
whatWentWrong (_:xs) = [] ++ whatWentWrong xs
函数inOrder (build x)
将返回x的排序版本(其中x是LogMessages列表)。显然我必须在开始使用whatWentWrong
处理列表之前对列表进行排序,或者我必须过滤掉所有不相关的消息(非错误的消息或者错误代码不超过50的消息),排序,然后从每个字符串中抓取字符串。
如果我没有关注这个例子,我只想定义另一个函数或者其他东西,或者只发送whatWentWrong
已排序的列表。但我想有一些理由这样做(我无法弄清楚)。
无论如何,我做了什么,为什么程序这么慢是这样的:
第ys /= inOrder (build ys)
行检查LogMessage列表每次遇到与错误模式匹配的LogMessage时都会按排序,即使在第一次检查失败后,列表也已排序好的。
这是我能想到的唯一方法。真的,我想要做的就是对它进行一次排序,但是我不知道如何使用我的排序函数对该列表进行排序,然后又不再执行该步骤。我显然没有正确地考虑这一点,任何帮助都表示赞赏。感谢。
答案 0 :(得分:3)
你真的需要一个单行列表理解:
whatWentWrong xs = [ msg | (LogMessage (Error code) _ msg) <- inOrder (build xs), code > 50]
如果要对列表进行排序以查看列表是否已排序,您也可以直接在排序列表上进行操作。完成后,列表推导将自动过滤掉未匹配模式的元素,code > 50
过滤其余元素。
如果您想将当前代码修复为练习,您只需要定义一个辅助函数,该函数假定其输入已排序。
whatWentWrong :: [LogMessage] -> [String]
whatWentWrong ys = www (inOrder (build ys))
where www [] = []
www ((LogMessage (Error code) _ msg):xs) | code > 50 = msg : www xs
| otherwise = www xs
www (_:xs) = www xs
但是,您应该认识到www
是组合
map
和filter
。
whatWentWrong ys = map f $ filter p (inOrder (build ys))
where p (LogMessage (Error code) _ _) = code > 50
p _ = False
f (LogMessage _ _ msg) = msg
或者,无点样式
whatWentWrong = map f . filter p . inOrder . build
where p (LogMessage (Error code) _ _) = code > 50
p _ = False
f (LogMessage _ _ msg) = msg