怎么做Seq.unzip

时间:2016-05-04 18:04:58

标签: f#

我有foo: seq<int*int>

我想拆分元组,然后将结果存储到两个变量中,每个变量为seq<int>

我想知道是否有更好的方法来做到这一点,例如。

let item1, item2 = foo |> ?????

我目前的解决方案:

let item1 = foo |> Seq.map(fun (f1,_) -> f1)
let item2 = foo |> Seq.map(fun (_,f2) -> f2)

4 个答案:

答案 0 :(得分:7)

可悲的是,虽然Lists(Seq.unzip)和Arrays(List.unzip)的等价物确实存在,但该语言中没有插入Array.unzip函数。

有几种方法可以定义这样的函数,其中一种方法是:

let unzip sequence =
    let (lstA, lstB) = 
        Seq.foldBack (fun (a,b) (accA, accB) -> 
            a::accA, b::accB) sequence ([],[])
    (Seq.ofList lstA, Seq.ofList lstB)

或者,如果您不关心在列表之间来回切换,您可以这样做:

let item1, item2 = 
    let it1, it2 = 
        foo 
        |> List.ofSeq 
        |> List.unzip 
    (Seq.ofList it1, Seq.ofList it2)

答案 1 :(得分:3)

你想得到的是两个不同的序列,所以你找不到更漂亮的方法来做到这一点。你拥有的东西几乎已经足够了,但你可以通过使用fstsnd分别修饰元组的第一和第二项,并将两个表达式写在同一行上来缩短它:

let items1, items2 = foo |> Seq.map fst, foo |> Seq.map snd

答案 2 :(得分:3)

对于列表和数组,这些函数是内置的:

> [(1, "foo"); (2, "bar"); (3, "baz")] |> List.unzip;;
val it : int list * string list = ([1; 2; 3], ["foo"; "bar"; "baz"])
> [|(1, "foo"); (2, "bar"); (3, "baz")|] |> Array.unzip;;
val it : int [] * string [] = ([|1; 2; 3|], [|"foo"; "bar"; "baz"|])

Seq并不存在。

答案 3 :(得分:2)

要添加TheInnerLight的答案,official documentation告诉我们:

  

Seq.zip和Seq.zip3采用两个或三个序列并产生一系列元组。这些功能类似于列表可用的相应功能。没有相应的功能将一个序列分成两个或多个序列。 如果序列需要此功能,请将序列转换为列表并使用List.unzip

我的自发解决方案(类似于OP的方法)应该写:

let unzip sequence = 
    let source = Seq.cache sequence
    Seq.map fst source, Seq.map snd source

(我在FSI中测试了1000000个元素,它也比我的计算机上的List.unzip方法慢一点)