我有一个 foo: seq<int*int>
我想拆分元组,然后将结果存储到两个变量,每个变量a seq<int>
我想知道是否有更好的方法来做到这一点,例如
let item1, item2 = foo |> ?????
Run Code Online (Sandbox Code Playgroud)
我目前的解决方案
let item1 = foo |> Seq.map(fun (f1,_) -> f1)
let item2 = foo |> Seq.map(fun (_,f2) -> f2)
Run Code Online (Sandbox Code Playgroud)
遗憾的是Seq.unzip,虽然Lists(List.unzip)和Arrays(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)
Run Code Online (Sandbox Code Playgroud)
或者,如果您不关心在列表之间来回切换,您可以这样做:
let item1, item2 =
let it1, it2 =
foo
|> List.ofSeq
|> List.unzip
(Seq.ofList it1, Seq.ofList it2)
Run Code Online (Sandbox Code Playgroud)
您想要得到的是两个不同的序列,因此您找不到更漂亮的方法来做到这一点。fst你所拥有的几乎足够了,但是你可以通过使用和snd分别来戏弄元组的第一个和第二个项目,并将两个表达式写在同一行上,从而使其更短一些:
let items1, items2 = foo |> Seq.map fst, foo |> Seq.map snd
Run Code Online (Sandbox Code Playgroud)
为了补充 TheInnerLight 的答案,官方文档告诉我们:
Seq.zip 和 Seq.zip3 采用两个或三个序列并生成元组序列。这些函数类似于可用于列表的相应函数。没有相应的功能将一个序列分成两个或多个序列。如果您需要序列的此功能,请将序列转换为列表并使用 List.unzip。
我自发的解决方案(类似于OP的方法)是这样写:
let unzip sequence =
let source = Seq.cache sequence
Seq.map fst source, Seq.map snd source
Run Code Online (Sandbox Code Playgroud)
(我在 FSI 中测试了 1000000 个元素,它也比我的计算机上的 List.unzip 方法慢一点)