2012-10-07 15 views
5

Załóżmy, że mam sekwencję sekwencji, np.Pivot lub zip a seq <seq<'a>> w F #

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

Jaki jest najlepszy sposób, aby obracać lub zip tej sekwencji, więc zamiast tego,

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

Czy istnieje zrozumiały sposób robić to bez uciekania się do manipulacji leżącej IEnumerator<_> typu?

Aby wyjaśnić, są to obiekty seq<seq<int>>. Każda sekwencja (zarówno wewnętrzna, jak i zewnętrzna) może mieć dowolną liczbę elementów.

+0

Więc chcesz zrobić transpozycję macierzy lub grupę przez element - to nie jest bardzo jasny. Przykład dla dłuższego wejścia byłby dobry. –

+1

możliwy duplikat [Jak napisać funkcję podobną do ZipN w F #?] (Http://stackoverflow.com/questions/11770441/how-do-i-write-a-zipn-like-function-in-f) – Daniel

Odpowiedz

3

Jeśli szukasz rozwiązania, które jest semantyczne Seq, będziesz musiał być leniwy przez cały czas.

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 

Test:

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

wyjściowa:

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

, podczas gdy to zadziała, Seq.groupBy nie jest leniwy i w pełni oceni jego sekwencje wejściowe, gdy pierwszy element zostanie zażądany od Seq.groupBy –

1

To wydaje się bardzo nieeleganckie, ale robi właściwą odpowiedź:

(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

Wygląda obiecująco, ale jak przekonwertować seq > do seq , aby użyć tej metody? – bytebuster

+0

Pytanie OP wymaga, aby rozwiązanie działało na sekwencji sekwencji o zmiennej długości, a nie sekwencji n-krotek. – Asti

0

Wygląda transpozycję macierzy.

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 

Alternatywnie, można przyjąć taką samą metodę seq, dzięki this answer na elegancki Aktywny wzór:

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 

Zobacz również this answer do szczegółów technicznych oraz dwie referencje: do PowerPack „s Microsoft.FSharp.Math.Matrix i jeszcze inna metoda obejmująca zmienne dane.

+0

To jednak ocenia wszystkie sekwencje z entuzjazmem. 'Seq.ofList' nie robi nic, tylko rzuca listę na' seq <'t> ', więc nie ma większego sensu posiadanie podpisu jako' seq > '. – Asti

0

Jest to ta sama odpowiedź jak @Asti, po prostu oczyścić trochę:

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