计算排序列表中的元素数量,它们大于给定谓词

时间:2013-04-25 08:58:03

标签: sml

我正在尝试创建一个函数,该函数查找在给定的排序列表中有多少元素大于第一个元素除以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

2 个答案:

答案 0 :(得分:3)

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

  • 首先你不应该使用引用(除非你知道你在做什么,当时它可能仍然是错误的),你应该使用递归。
  • 您尚未声明您的函数采用相同数量的参数。在第一个子句中,您已使用2个curried参数定义它,在其余的子句中只有一个参数,在第二行代码中,您使用一对作为参数调用该函数。
  • 您的第一个函数子句没有正文。
  • "<"不是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

答案 1 :(得分: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