【问题标题】:Counting how many elements in a sorted list, that are larger than a given predicate计算排序列表中有多少元素大于给定谓词
【发布时间】:2013-04-26 17:55:52
【问题描述】:

我正在尝试创建一个函数,该函数在给定的排序列表中查找大于第一个元素除以2 的元素数。例如给定一个列表[3,3,4,5,6,7,8,9,11],第一个元素是3,大于2的数字是7,8,9,11,所以函数返回4

到目前为止我已经这样做了,但它不起作用。 a 元素是列表的第一个元素,是为了更容易而给出的。

fun findlarger a [] =
  | findlarger [] = 0
  | findlarger [x] = 0
  | findlarger (x::xs) =
    let
      val a = ref a;
    in
      if !a < x/2 then length (xs) + 1 else findlarger (a, xs)
    end

【问题讨论】:

    标签: sml


    【解决方案1】:

    我什至不知道从哪里开始指出您的代码存在的问题。您似乎误解了函数式编程的基础知识。

    • 首先,您不应该使用引用(除非您知道自己在做什么,否则它可能仍然是错误的),您应该使用递归。
    • 您尚未声明您的函数采用相同数量的参数。在第一个子句中,您使用 2 个 curried 参数定义了它,在其余子句中您只有一个参数,在代码的倒数第二行中,您使用一对作为参数调用函数。
    • 您的第一个函数子句没有主体。
    • "&lt;" 不是 sml 中的严格小于运算符。正如你在那里写的,它是一个字符串。

    修复您的原始代码将导致类似这样的结果。请注意,第一个元素总是被放回列表中,这样我们就知道要比较什么。

    fun findlarger [] = 0
      | findlarger [x] = 0
      | findlarger (x::y::xs) =
        if y > x*2 then
          1 + findlarger(x :: xs)
        else
          findlarger(x :: xs)
    

    但是,您也可以使用内部辅助函数来完成 x*2 的计算,这样就不会每次都计算了

    fun findlarger [] = 0
      | findlarger (x::xs) =
        let
          val xx = 2*x
          fun f [] = 0
            | f (y::ys) =
              (if y > xx then 1 else 0) + f ys
        in
          f xs
        end
    

    如果使用另一个答案中建议的高阶函数,那么您应该避免遍历列表两次(首先过滤掉元素,然后计算剩余的元素)。您应该只浏览一次列表,然后计算与给定谓词匹配的元素。
    要完成此功能,您可以使用其中一种折叠功能。在大多数情况下,使用 foldl 是有意义的,因为它将以尾递归的方式从左到右遍历列表。

    fun p (x, y) = if y > 2*x then 1 else 0
    
    fun f [] = 0
      | f (x::xs) = foldl (fn (a,b) => b + p(x, a)) 0 xs
    

    【讨论】:

    • 这个解决方案适用于小整数,但是一些测试用例有大整数,它会抛出一个错误未捕获异常溢出[溢出]。我的一个朋友指出问题出在 2*x 上。他说我不应该像这样 yy 那样进行比较,但这还有其他问题,因为它必须是真实的,并且必须进行一些汇总才能实现比较..
    【解决方案2】:

    试试这个解决方案:

    fun find lst =
        case lst of
            [] => 0
          | x::_ => List.length(List.filter(fn e => e > 2 * x) lst)
    

    用法:

    find [3,3,4,5,6,7,8,9,11] => 4
    

    【讨论】:

    • 遗憾的是,你只是给了他一个解决方案,却没有解释为什么它有效,或者更糟糕的是解释了为什么他的原始代码不能完成这项工作。
    • @Jesper.Reenberg 我认为给出解释的解决方案很明显
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-14
    • 2018-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多