函数返回最大邻居的索引

时间:2010-07-10 20:00:46

标签: function syntax f# design-patterns

F#功能

问题:

给出一个项目列表,例如:

["5";"10";"2";"53";"4"]

和搜索索引,我需要一个函数,它将当前给定的索引与其邻居进行比较,返回最大的索引

示例:

  • 鉴于索引1将返回索引值2(因为10大于5)。
  • 鉴于指数4将返回指数4(因为53大于4)

目前这是我的功能。它不编译:

let GetMaxNode (x:Array) Idx = if x.[Idx] > x.[Idx+1] then  Idx else If  x.[Idx] < x.[Idx+1] then  Idx+1

我得到的所有x'的错误是:

The field, constructor or member 'Item' is not defined (FS0039)

还有第二个If:

The value or constructor 'If' is not defined (FS0039)

我怀疑我仍在以程序方式思考,我正在考虑使用模式匹配,但是我对语法没有足够的信心来尝试它。

请你也解释答案,因为我正在努力学习F#,只是解决方案对我没什么帮助。

4 个答案:

答案 0 :(得分:3)

以下是一些基于你的代码:

let GetMaxNode (x:_[]) idx = 
    if x.[idx] > x.[idx+1] then  
        idx 
    elif x.[idx] < x.[idx+1] then  
        idx+1 
    else
        idx // same, return this one

主要变化是

  • 声明一个数组类型,比如<typename> []。在这种情况下,我们不关心类型,所以我使用_作为“不关心,请为我推断正确的”类型变量。
  • “else if if”拼写为elif在F#
  • 如果等于
  • 则需要else个案

答案 1 :(得分:3)

很难在函数式中为您的问题编写解决方案,因为您的问题是根据索引定义的 - 当使用功能数据结构(例如列表)时,您通常不会通过索引引用元素。

例如,问题的功能版本是,当当前位置的元素大于下一个元素时,创建一个包含true的列表,当它小时,创建false。对于您的数据,这将给出:

let data = [ 5;     10;   2;     53;   4 ]
let res  = [ false; true; false; true; ] // no item to compare '4' with 

使用遍历列表和模式匹配的递归函数可以很好地解决这个问题(因为模式匹配对于函数列表比使用数组更好)

let rec getMaxNodes data = 
  match data with 
  // list has at least two elements and current is larger
  | current::next::other when current >= next ->
      // process the rest of the list
      let rest = (getMaxNodes (next::other))
      // return 'true' followed by recursively processed rest of the list
      true::rest
  // list has at least two elements and current is smaller
  | current::next::rest ->
      // same as the previous case, but we return false
      false::(getMaxNodes (next::rest))
  | _ -> 
      // one element (so we cannot compare it with the next one)
      // or empty list, so we return empty list
      []

getMaxNodes data

答案 2 :(得分:2)

以下是Brian回答的模式匹配版本。

let GetMaxNode (x:_[]) idx =
    match idx with
    | idx when x.[idx] > x.[idx+1] -> idx
    | idx when x.[idx] < x.[idx+1] -> idx + 1
    | idx -> idx // same, return this one

当您查看更多F#代码时,您可能还会看到语法快捷方式。以下代码在功能上与上面的代码完全相同。

let GetMaxNode (x:_[]) = function
    | idx when x.[idx] > x.[idx+1] -> idx
    | idx when x.[idx] < x.[idx+1] -> idx + 1
    | idx -> idx // same, return this one

答案 3 :(得分:0)

每当你开始讨论索引时,你最好坚持使用Arrays或ResizeArrays; F#列表不适合索引上的操作,因为它们是从头到尾单链接的。话虽如此,通过使用递归循环遍历列表并跟踪当前索引和当前元素,以纯函数方式编写此算法并不困难。

let find elements index =
    //a local tail-recursive function hides implementation details
    //(cur::tail) is a pattern match on the list, i is the current index position
    let rec loop (cur::tail) i =
        if i = index then //when the current index matches the search index
            if cur >= tail.Head then i //compare cur to tail.Head (which is next)
            else (i+1)
        else loop tail (i+1) //else continue
    loop elements 0 //the entry point of loop and our return value

使用整数列表而不是字符串来获得您期望的结果(因为“10”实际上小于“5”):

> let x = [5;10;2;53;4];;
> find x 0;;
val it : int = 1
> find x 1;;
val it : int = 1
> find x 2;;
val it : int = 3
> find x 3;;
val it : int = 3