找到列表列表的最大值

时间:2016-10-29 19:40:02

标签: ocaml

有没有办法找到列表列表的最大值? 例如

word = 'busboi'
guesses = 'bs'

word.tr('^'+guesses, '-')
# => "b-sb--"

将输出:^

3 个答案:

答案 0 :(得分:2)

  

我正在考虑使用模式匹配,但它似乎是噩梦般的

let rec lmax list = match list with
    | [] -> None
    | x :: xs -> Pervasives.max (Some x) (lmax xs)

但该函数不是尾递归的。 函数参数之间的评估顺序是未定义的,但基本上你计算这样的事情:

-> Evaluate (Some x)
-> Evaluate (lmax xs)
   ...recursion...
<- Then, compute max

我们必须计算并记住每次调用lmax的中间值。 另一种方法是使用辅助递归函数aux,它采用累加器acc

let lmax list = 
  let rec aux list acc = match list with
    | [] -> acc
    | x :: xs -> (aux xs (Pervasives.max acc (Some x)))
  in (aux list None)

然后,我们不需要存储中间值:

-> Evaluate xs
-> Compute max of current acc with (Some x)
-> ...recursion...

递归调用将计算当前值的结果,不需要记住中间值,这使得递归调用迭代。

折叠

以上是一种常见的模式,可以通过高阶函数抽象出来,称为 fold (或 reduce )。有两种 fold :上面的第一种是右侧折叠,带有累加器的那种是左侧折叠。 它们采用reduce函数,该函数根据先前的结果和值以及初始结果(对于空列表)计算新结果。 当reduce函数关联时,两种折叠计算相同的结果,并且由于其尾递归实现,建议尽可能使用左折叠。 当缩减函数为右关联时,使用右侧折叠,如cons。以下是List.map的重新实现:

let my_map fn list = List.fold_right (fun x xs -> (fn x) :: xs) list []

Lmax的

因此,您可以使用左侧折叠计算列表的最大值:

let lmax list = 
  List.fold_left  
    (fun max x -> Pervasives.max max (Some x))
    None
    list

option类型是必要的,因为空列表没有最大值(您也可以返回最大的负整数)。

LLmax

现在,您还可以使用折叠计算列表列表的最大值:

let llmax list =
  List.fold_left 
    (fun max list -> Pervasives.max max (lmax list))
    None 
    list;;

对于列表列表中的每个元素,我们计算得到lmax的最大值并生成到目前为止看到的最大值。

llmax [[1; 2; 3; -4; -2; 0]; [1; 2; -5; -3; -1]]
- : int option = Some 3

LL ...最大

如果要概括,可以编写一个foldmax函数,该函数由一个函数参数化,该函数计算列表元素的最大值:

let foldmax fn list =
  List.fold_left
  (fun max x -> Pervasives.max max (fn x))
  None
  list

val foldmax : ('a -> 'b option) -> 'a list -> 'b option = <fun>

最后,您可以使用此辅助功能重写lmaxllmaxlllmax等):

let lmax list = foldmax (fun x -> Some x) list
let llmax list = foldmax lmax list
let lllmax list = foldmax llmax list

答案 1 :(得分:1)

在命令式/过程式语言中,您可以遍历列表并与最大数字进行比较,即

def max(lst):
  max = None
  for l in lst:
     for x in l:
        if max is None or x > max:
          max = x
  return max

(显然不是惯用的,只是尽可能明确这一点)

在OCaml中,你会做类似的事情,但使用一种称为“折叠”(一种函数)的东西,这是对上述想法的抽象。

let max list = 
  let f max x = 
    match max with
    | None -> Some x
    | Some m -> if m > x then Some m else Some x
  in
  List.fold_left f None (List.flatten list)

答案 2 :(得分:0)

let max l =
  List.fold_left (fun max x ->
    Pervasives.max  max (Some x)
  ) None (List.flatten l)

<强>测试

#  max [[1; 2; 3; -4; -2; 0]; [1; 2; -5; -3; -1]];;
- : int option = Some 3

# max [];;
- : 'a option = None

<强>评论

Pervasives.max发现最多两个选项:

# Pervasives.max None (Some (-1));;
- : int option = Some (-1)

List.flatten:连接列表列表

# List.flatten [[1; 2; 3; -4; -2; 0]; [1; 2; -5; -3; -1]];;
- : int list = [1; 2; 3; -4; -2; 0; 1; 2; -5; -3; -1]