简体   繁体   English

Haskell函数对输入列表进行排序,然后对排序后的列表进行处理

[英]Haskell function sort input list then do stuff with sorted list

Short version: 简洁版本:

I want to sort a list, and then perform operations on that sorted list that filter/extract data to form a new list, all in one function. 我想对一个列表进行排序,然后对该排序后的列表执行操作,以过滤/提取数据以形成一个新列表,所有这些功能都是一样的。

Long version: 长版:

I am teaching myself Haskell using these lessons . 我正在使用这些课程自学Haskell。 I'm currently on Homework 2 Exercise 5. 我目前正在做作业2练习5。

I am required to write a function whatWentWrong that takes an unsorted list of LogMessages and returns a list of Strings. 我需要编写一个函数whatWentWrong ,该函数采用whatWentWrong未排序列表并返回字符串列表。 The strings are the String portion of LogMessages that were constructed with Error in which the Error code is > 50. They are supposed to be sorted by the TimeStamp portion of LogMessage. 字符串是用Error构造的LogMessages的String部分,其中Error代码大于50。它们应该按LogMessage的TimeStamp部分排序。

I have a function written for whatWentWrong that works, but it's really really slow (you'll see why). 我有一个针对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

The functions inOrder (build x) will return a sorted version of x (where x is a list of LogMessages). inOrder (build x)函数将返回inOrder (build x)的排序版本(其中x是LogMessages列表)。 Obviously I have to either sort the list before I begin processing it with whatWentWrong , or I have to filter out all non relevant messages (Messages which are not Errors or which don't have Error codes above 50), sort, and then grab the strings from each one. 显然,我必须先对列表进行排序,然后再使用whatWentWrong处理它,或者必须过滤掉所有不相关的消息(不是错误或错误代码不超过50的消息),然后进行排序,然后抓取每个字符串。

If I wasn't following this example, I would just define another function or something, or just send whatWentWrong an already sorted list. 如果我不遵循此示例,则可以定义另一个函数或其他内容,或者仅发送一个已经排序的列表whatWentWrong But I imagine there's some reason to do it this way (which I can't figure out). 但我想有某种理由这样做(我不知道)。

Anyways, what I've done, and why the program is so slow is this: The line ys /= inOrder (build ys) is checking that the LogMessage list is sorted every single time it encounters a LogMessage that matches the Error pattern , even though, after the first time that check fails, the list is sorted for good. 无论如何,我所做的事情以及程序为何如此缓慢的原因是: ys /= inOrder (build ys) 每次遇到与Error模式匹配的LogMessage时,都会检查LogMessage列表是否已排序,甚至但是,在第一次检查失败后,该列表将被排序。

That's the only way I could think to do it. 那是我唯一想到的方法。 Really, what I want to do it sort it once, but I have no idea how to make the function sort the list using my sorting functions and then not do that step ever again. 确实,我想对它进行一次排序,但是我不知道如何使该函数使用我的排序函数对列表进行排序,然后再也不执行该步骤。 I'm obviously not thinking about this correctly and any help is appreciated. 我显然没有正确地考虑这个问题,我们将不胜感激。 Thanks. 谢谢。

You really just need a one-line list comprehension: 您实际上只需要单行列表理解:

whatWentWrong xs = [ msg | (LogMessage (Error code) _ msg) <- inOrder (build xs), code > 50]

If you are sorting the list to see if the list is sorted, you may as well just work directly on the sorted list. 如果要对列表进行排序以查看列表是否已排序,则也可以直接在已排序的列表上工作。 Once you've done that, the list comprehension will automatically filter out the elements that don't pattern match, and the code > 50 filters the rest. 完成此操作后,列表推导将自动过滤掉与模式不匹配的元素,而code > 50过滤其余部分。


If you want to fix your current code as an exercise, you just need to define a helper function that assumes its input is sorted. 如果您想通过练习来修复当前代码,则只需定义一个帮助程序函数(假定其输入已排序)即可。

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

However, you should recognize that www is the combination of a map and a filter . 但是,您应该认识到wwwmapfilter的组合。

whatWentWrong ys = map f $ filter p (inOrder (build ys))
                   where p (LogMessage (Error code) _ _) = code > 50
                         p _ = False
                         f (LogMessage _ _ msg) = msg

or, in point-free style 或者,以无点样式

whatWentWrong = map f . filter p . inOrder . build
                where p (LogMessage (Error code) _ _) = code > 50
                      p _ = False
                      f (LogMessage _ _ msg) = msg

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM