F#

2012-10-07 47 views
5

我們假設我有一系列的序列,例如,F#

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

什麼是轉動或壓縮這個序列,所以我反而有最好的方式,

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

有沒有這樣做,而不訴諸底層IEnumerator<_>類型的操縱的理解呢?

要澄清,這些是seq<seq<int>>對象。每個序列(內部和外部)可以有任意數量的項目。

+0

所以你要做一個矩陣轉置或一個元素組合 - 這不是很好明確。一個更長的輸入的例子是好的。 –

+1

[我如何在F#中編寫類似ZipN的函數?]的可能重複(http://stackoverflow.com/questions/11770441/how-do-i-write-a-zipn-like-function-in-f ) – Daniel

回答

3

如果您要尋找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]] 
+1

雖然這將工作,但Seq.groupBy不是懶惰的,並且一旦從Seq.groupBy請求第一個元素,就會完全評估它的輸入序列 –

1

這似乎非常不雅,但它得到正確的答案:

(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::[] 
+0

它看起來很有前途,但是如何將seq >轉換爲seq 以使用此方法? – bytebuster

+0

OP的問題需要解決方案對可變長度的序列進行操作,而不是一系列n元組。 – Asti

0

它看起來像矩陣轉置。

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一個優雅的活動模式:

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和涉及可變數據的另一種方法

+0

儘管如此,它仍然對所有的序列進行了評估。 'Seq.ofList'什麼都不做,只是將列表強制轉換爲'seq <'t>',所以將簽名作爲'seq >'沒有多大意義。 – Asti

0

這是相同的答案@Asti,只是清理了一點:

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