【问题标题】:Get the last element of a list in f#获取 f# 中列表的最后一个元素
【发布时间】:2017-02-18 05:53:34
【问题描述】:

我想获取列表的最后一个元素,我的逻辑是反转列表并获取其头部:

module Program1 = 

    let last list =
        let newList=List.rev list;
        List.head newList;
        newList 

    let mainP1()=
        let list= [ 1; 2; 3] 
        printfn "Ultimul element al listei %A este %A" list (last list )

但它给了我这个错误

Error       Type mismatch. Expecting a
    unit list    
but given a
    int list    
The type 'unit' does not match the type 'int'   

谁能帮帮我?

【问题讨论】:

  • 有一个内置函数:List.last。这是作业吗?

标签: .net list function f# reverse


【解决方案1】:

这里有很多东西要解压。

首先,您的函数没有返回您希望它返回的内容。看到最后一行,上面写着newList 吗?那是你的函数的返回值。函数体的最后一行是它的返回值。因此,您返回的是反向列表,而不是最后一个元素。

第二,由于您没有返回List.head 调用的结果,因此您忽略它。没有做任何事情的结果。无视。 F# 编译器在这里试图帮助你:如果你忽略了一个值,这意味着你做错了,如果你这样做,F# 会抱怨(发出警告)。

但该规则有一个例外:您可以忽略 unit 类型的值。逻辑是,如果你有一个unit 类型的值,你一定是因为产生了副作用而获得了它。因为如果没有副作用,也没有结果值(unit 表示“没有价值”),那么重点是什么?

因此,编译器会这样思考:如果您忽略了一个值,那么该值必须是unit 类型。由于List.head newList 是unit 类型,那么newList 必须是unit list 类型。因此,list 必须是 unit list 类型。因此,您的函数是 unit list -> unit list 类型(即,它接受 unit list 作为参数并返回另一个 unit list 作为结果)。

而且由于您试图将 int list 传递给采用 unit list 的函数,编译器无法忍受:Expecting a unit list but given a int list。

最后,为了得到最后一个值而反转列表是非常浪费的!您正在重新分配大量您并不真正需要的内存。实现这一点的一种不那么浪费的方法是使用递归。可以这样想:单元素列表的最后一个元素是那个元素,而较长列表的最后一个元素是其尾部的最后一个元素。我们可以直接在 F# 中编写:

let rec last list =
  match list with
  | [x] -> x   // The last element of one-element list is the one element
  | _::tail -> last tail   // The last element of a longer list is the last element of its tail
  | _ -> failwith "Empty list"   // Otherwise fail

另外,还有一个现成的函数List.last,你可以直接使用(除非这是家庭作业,在这种情况下你应该在问题中提及)。

let mainP1()=
  let list= [ 1; 2; 3] 
  printfn "Ultimul element al listei %A este %A" list (List.last list)

但请注意,如果列表为空,则列表中可能没有最后一个元素。在这种情况下,List.last(以及List.head)会崩溃并出现异常,这通常不是一个好主意。如果您需要处理空列表的情况,请查看List.tryLast:

let mainP1()=
  let list= [1; 2; 3] 
  match List.tryLast list with
  | Some x -> printfn "Ultimul element al listei %A este %A" list x
  | None -> printfn "Lista %A este goală" list

【讨论】:

  • 一个不可变的链表又名FSharp.Collections.List<'T> 对于随机访问来说效率不高:必须遍历整个链表,因此 O(n)。 List.rev 没有比这更好或更差。
  • @kaefer 你是对的。出于某种原因,我的印象是 F# 在性能上作弊,例如 the way it does with List.map,但显然情况并非如此。我将从答案中删除这一点。
猜你喜欢
  • 1970-01-01
  • 2022-01-01
  • 2012-10-21
  • 2010-10-30
  • 1970-01-01
  • 2022-11-15
  • 1970-01-01
  • 1970-01-01
  • 2018-08-25
相关资源
最近更新 更多