2012-10-07 6 views
5

Nehmen wir an, ich habe eine Sequenz von Sequenzen, z.Pivot oder zip a seq <seq<'a>> in F #

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

Was ist der beste Weg, oder diese Sequenz Reißverschluss zu schwenken, so dass ich stattdessen habe,

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

Gibt es eine nachvollziehbare Art und Weise, dies zu tun, ohne den zugrunde liegenden IEnumerator<_> Typen Manipulation zurückgreifen?

Zur Verdeutlichung sind dies seq<seq<int>> Objekte. Jede Sequenz (sowohl intern als auch extern) kann eine beliebige Anzahl von Elementen enthalten.

+0

So wollen Sie eine Matrix-Transposition oder Gruppe durch ein Element zu machen - das ist nicht sehr klar. Ein Beispiel für eine längere Eingabe wäre gut. –

+1

möglich duplicate of [Wie schreibe ich eine ZipN-ähnliche Funktion in F #?] (Http://stackoverflow.com/questions/11770441/how-do-i-write-a-zipnlike-function-in-f) – Daniel

Antwort

3

Wenn Sie eine Lösung suchen, die semantisch Seq ist, müssen Sie die ganze Zeit faul bleiben.

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) 

Ausgang:

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

Während dies funktioniert, ist Seq.groupBy nicht faul und wird seine Eingabesequenzen vollständig auswerten, sobald das erste Element von Seq.groupBy angefordert wird –

1

Dies scheint sehr unelegant, aber es wird die richtige Antwort:

(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

Es sieht vielversprechend aus, aber wie konvertiere ich seq > zu seq , um diese Methode zu verwenden? – bytebuster

+0

Die Frage von OP erfordert, dass die Lösung auf einer Sequenz von Sequenzen variabler Länge und nicht auf einer Sequenz von n-Tupeln operiert. – Asti

0

Es sieht aus wie die Matrixtrans.

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 

Alternativ können Sie die gleiche Methode für seq dank this answer für ein elegantes Aktiv Muster annehmen:

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 

Siehe auch this answer für technische Details und zwei Referenzen: auf Power ‚s Microsoft.FSharp.Math.Matrix und noch eine andere Methode mit veränderbaren Daten.

+0

Dies bewertet jedoch alle Sequenzen eifrig. 'Seq.ofList' tut nichts anderes, als die Liste auf 'seq <'t>' zu setzen, so dass es nicht viel Bedeutung hat, die Signatur als 'seq >' zu haben. – Asti

0

Dies ist die gleiche Antwort wie @Asti, nur ein wenig aufgeräumt:

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