5

我会做类似的事情

let last n xs = xs |> List.rev |> Seq.take n |> List.ofSeq |> List.rev

我不确定将列表转换为序列并返回。这是你如何做到的F#?

4

4 回答 4

5

顺序 + 跳过

取最后 N 个项目相当于跳过第一个 (length - N) 个项目,因此对于一个序列作为输入(和输出),您可以执行以下操作:

let last n xs = Seq.skip ((Seq.length xs) - n) xs

(或者,使用管道,let last n xs = xs |> Seq.skip (Seq.length xs - n)

对于作为输入(和输出)的列表,您可以执行以下操作:

let last n xs = List.toSeq xs |> Seq.skip (xs.Length - n) |> Seq.toList

或者通过定义两者,只需将其传递到序列一:

let lastList n xs = List.toSeq xs |> last n |> Seq.toList

尾+递归

或者,这可以通过 (tail) 递归应用 Tail 来实现,如下所示:

let rec last n xs =
  if List.length xs <= n then xs
  else last n xs.Tail
于 2013-09-07T05:57:52.897 回答
3

您可以使用List.foldBack从末尾遍历列表:

let takeLast n list = 
    let (_, r) = List.foldBack (fun e (i, acc) -> (i - 1, if i <= 0 then acc else e :: acc)) list (n, [])
    r
于 2013-09-07T09:41:38.320 回答
0

chamila_c 功能的变化:-

/// Returns the last abs(n) items in the specified sequence.
let lastN n xs =
    // The number to skip will be negative if n is too large; this will result in 0 items being skipped.
    // By taking abs(n), the number to skip can't get too large, and we avoid an exception being thrown.
    xs |> Seq.skip (Seq.length xs - abs n)
于 2014-12-09T16:33:28.580 回答
0

为避免重建列表,您可以使用简单的递归算法。

请注意,我们既不使用List.Cons也不使用Seq.toListwhich 在内部执行相同的操作。

let lastN n xs =
    let rec skip n xs = 
        match n, xs with
        | _, []     -> []   // empty list, returning unchanged
        | 0, _      -> xs   // found an element at which the remainder
                            // of the list is to be returned
        | n', h::t  -> skip (n-1) t    // proceed to next iteration

    let toSkip = (List.length xs) - n  // how many elements to skip
    if toSkip < 0 then xs   // or an exception, depending on expected behavior
    elif toSkip = 0 then xs // requested exactly as many elements
                            // as the list contains
    else skip toSkip xs

// usage
let data = [1 .. 10000000]
let stopWatch = new System.Diagnostics.Stopwatch()
stopWatch.Start()
data
|> lastN 3
|> List.iter (printf "%d ")
stopWatch.Stop()
printfn "\nelapsed: %f ms" stopWatch.Elapsed.TotalMilliseconds

输出:

9999998 9999999 10000000
elapsed: 194.846700 ms
于 2013-09-07T11:05:42.267 回答