递归地将列表解包为元素

4

我有一个列表,希望能够逐个返回其中的元素。类似于从栈中弹出元素一样。例如:

let rnd = new System.Random()
let rnds = List.init 10 (fun _ -> rnd.Next(100))
List.iter (fun x -> printfn "%A"x ) rnds

不过,与其进行迭代,我想要的是在列表为空之前,每次返回一个整数。基本上就像这样:

List.head(rnds)
List.head(List.tail(rnds))
List.head(List.tail(List.tail(rnds)))
List.head(List.tail(List.tail(List.tail(List.tail(rnds)))))

很遗憾,我尝试使用递归或者更好的fold或scan解决方案都失败了。例如,这只返回列表(与map相同)。

let pop3 (rnds:int list) =
    let rec pop3' rnds acc =
        match rnds with
        | head :: tail -> List.tail(tail)
        | [] -> acc
    pop3' [] rnds
2个回答

5
你需要的是uncons吗?
let uncons = function h::t -> Some (h, t) | [] -> None

你可以使用它来“弹出”列表的头部:
> rnds |> uncons;;
val it : (int * int list) option =
  Some (66, [17; 93; 33; 17; 21; 1; 49; 5; 96])

你可以重复这个步骤:
> rnds |> uncons |> Option.bind (snd >> uncons);;
val it : (int * int list) option = Some (17, [93; 33; 17; 21; 1; 49; 5; 96])
> rnds |> uncons |> Option.bind (snd >> uncons) |> Option.bind (snd >> uncons);;
val it : (int * int list) option = Some (93, [33; 17; 21; 1; 49; 5; 96])

是的,确实,这也是一个非常有趣的解决方案。非常感谢。 - s952163

2

这似乎是一个很好的班级机会

type unpacker(l) = 
    let mutable li = l
    member x.get() = 
        match li with
        |h::t -> li<-t;h
        |_ -> failwith "nothing left to return"

所以我会这样使用它:let xx = unpacker(rnds) xx.get()[for i in 1..5 -> xx.get()]。我添加了override this.ToString() = sprintf "%A" l,使其更加用户友好。 - s952163

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接