【问题标题】:Pivot or zip a seq<seq<'a>> in F#在 F# 中旋转或压缩 seq<seq<'a>>
【发布时间】:2012-09-27 19:23:43
【问题描述】:

假设我有一个序列序列,例如

{1, 2, 3}, {1, 2, 3}, {1, 2, 3}

什么是旋转或压缩这个序列的最佳方式,所以我有,

{1, 1, 1}, {2, 2, 2}, {3, 3, 3}

有没有一种可以理解的方法来做到这一点,而无需操纵底层的IEnumerator&lt;_&gt; 类型?

为了澄清,这些是seq&lt;seq&lt;int&gt;&gt; 对象。每个序列(内部和外部)可以有任意数量的项目。

【问题讨论】:

标签: f# functional-programming pivot sequence


【解决方案1】:

这和@Asti的答案一样,只是稍微整理了一下:

[[1;2;3]; [1;2;3]; [1;2;3]] 
    |> Seq.collect Seq.indexed 
    |> Seq.groupBy fst 
    |> Seq.map (snd >> Seq.map snd);;

【讨论】:

    【解决方案2】:

    如果您要寻求语义 Seq 的解决方案,您将不得不一直保持懒惰。

    let zip seq = seq
                |> Seq.collect(fun s -> s |> Seq.mapi(fun i e -> (i, e))) //wrap with index
                |> Seq.groupBy(fst) //group by index
                |> Seq.map(fun (i, s) -> s |> Seq.map snd) //unwrap
    

    测试:

    let seq =  Enumerable.Repeat((seq [1; 2; 3]), 3) //don't want to while(true) yield. bleh.
    printfn "%A" (zip seq)
    

    输出:

    seq [seq [1; 1; 1]; seq [2; 2; 2]; seq [3; 3; 3]]
    

    【讨论】:

    • 虽然这会起作用,但 Seq.groupBy 并不懒惰,一旦从 Seq.groupBy 请求第一个元素,它将完全评估其输入序列
    • Seq.mapi (fun i e -&gt; (i, e))Seq.indexed 一样吗? (fsharp.github.io/fsharp-core-docs/reference/…)——编辑:是的——见约书亚回答
    【解决方案3】:

    看起来像矩阵转置。

    let data =
        seq [
            seq [1; 2; 3]
            seq [1; 2; 3]
            seq [1; 2; 3]
        ]
    
    let rec transpose = function
        | (_::_)::_ as M -> List.map List.head M :: transpose (List.map List.tail M)
        | _ -> []
    
    // I don't claim it is very elegant, but no doubt it is readable
    let result =
        data
        |> List.ofSeq
        |> List.map List.ofSeq
        |> transpose
        |> Seq.ofList
        |> Seq.map Seq.ofList
    

    或者,您可以对 seq 采用相同的方法,感谢 this answer 的优雅 Active 模式:

    let (|SeqEmpty|SeqCons|) (xs: 'a seq) =
      if Seq.isEmpty xs then SeqEmpty
      else SeqCons(Seq.head xs, Seq.skip 1 xs)
    
    let rec transposeSeq = function
        | SeqCons(SeqCons(_,_),_) as M ->
            Seq.append
                (Seq.singleton (Seq.map Seq.head M))
                (transposeSeq (Seq.map (Seq.skip 1) M))
        | _ -> Seq.empty
    
    let resultSeq = data |> transposeSeq
    

    另请参阅 this answer 了解技术细节和两个参考:PowerPackMicrosoft.FSharp.Math.Matrix 和涉及可变数据的另一种方法。

    【讨论】:

    • 这会急切地评估所有序列。 Seq.ofList 只是将列表转换为seq&lt;'t&gt;,因此将签名设置为seq&lt;seq&lt;'t&gt;&gt; 没有太大意义。
    【解决方案4】:

    这看起来很不优雅,但它得到了正确的答案:

    (seq [(1, 2, 3); (1, 2, 3); (1, 2, 3);]) 
    |> Seq.fold (fun (sa,sb,sc) (a,b,c) ->a::sa,b::sb,c::sc) ([],[],[]) 
    |> fun (a,b,c) -> a::b::c::[]
    

    【讨论】:

    • 看起来很有希望,但是如何将 seq> 转换为 seqintint> 以使用此方法?
    • OP 的问题要求解决方案对可变长度的序列序列进行操作,而不是对 n 元组序列进行操作。
    猜你喜欢
    • 1970-01-01
    • 2014-08-25
    • 1970-01-01
    • 2019-03-03
    • 2021-08-31
    • 2012-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多