繁体   English   中英

Haskell 从列表中删除最大数

[英]Haskell delete largest number from a list

我想弄清楚如何创建一个递归函数,该函数将找到列表中最大的元素并删除它然后返回列表。 这是我到目前为止所拥有的,但问题是每次我运行它时,它都会返回没有分配给 x 的任何值的列表。

deleteMax :: (Ord a) => [a] -> [a]
deleteMax  [] = []
deleteMax [x] = []
deleteMax (x:y:xs) 
    |x == y = y: deleteMax xs 
    |x >= y = y: deleteMax xs
    |x < y = x: deleteMax xs

这不是你的答案

因此,您是初学者,因此想要“如何找到列表中最大的元素”的简单解决方案,然后是“如何删除列表中的(一个)最大元素”。 这不是那个答案,而是我避免了冗长的评论,同时也给了你一些可以在 3 个月内回来的东西。

懒惰的方式

@nm 和我在评论中争论的一个解决方案是打结(Googleable 术语)。 在这种方法中,您只需要对列表进行一次逻辑传递。 在这种情况下,隐藏构建结果列表的过程基本上是一个技巧。

这个想法是,在你传递列表的过程中,你完成了 1. 计算最大元素和 2. 与最大元素比较并构建列表的两个任务。 这里没有任何需要 monad 的东西,但最容易将其视为状态 monad 的一部分:

deleteMaxState :: (Ord a) => [a] -> [a]
deleteMaxState []       = []

首先我们处理基本情况,所以我们有一个候选的“最大值”( x )用于我们的递归操作。

deleteMaxState xs@(fstElem:_) =
    let (r,(m,_)) = runState (go xs) (fstElem, notMax m)
        notMax mx v = if (mx > v) then (v:) else id
        go [] = return []
        go (x:xs) =
            do (curr,f) <- get
               when (x > curr) (put (x,f))
               f x <$> go xs
    in r

在循环中,我们跟踪两个值,第一个值curr是我们遍历列表中的这一点的最大观察值。 第二个值f是技巧——它是(一个函数)在遍历完成提供给计算的最大值。

神奇之处就在这里:

(r,(m,_)) = runState (go xs) (fstElem, m)

结果状态(m,_)的左侧元素是我们的运行最大值。 一旦遍历结束,我们就使用该值 - 它成为正确的元素(fstElem, m) ,从而代表整个列表的最大值。

我们可以使用f来创建填充列表部分的 thunk,或者只是将我们的列表构建为一堆未评估的cons计算。

使这个更简单,我们可以删除高阶函数f并只有一个数字(未经测试):

deleteMaxState xs@(fstElem:_) =
    let (r,(m,_)) = runState (go xs) (fstElem, m)
        go [] = return []
        go (x:xs) =
            do (curr,theMax) <- get
               when (x > curr) (put (x,theMax))
               ((if x >= theMax then Nothing else Just x) :) <$> go xs
    in catMaybes r

现在我们可以非常明确地看到第二次传递不仅仅是一组未评估的“一些涉及最大值的计算,根据结果”,而是作为通过catMaybes的实际传递。

打结允许程序员编写一个逻辑遍历。 这可能很好,因为它只需要一个模式匹配和每个列表元素构造函数的递归调用,但代价是推理评估顺序。

暂无
暂无

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

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