2012-10-07 38 views
5

Digamos que tengo una secuencia de secuencias, p.Pivote o zip a seq <seq<'a>> en F #

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

Lo que hay es la mejor manera de pivotar o zip esta secuencia así que en su lugar tienen,

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

es una forma comprensible de hacerlo sin recurrir a la manipulación de la IEnumerator<_> tipo subyacente?

Para aclarar, estos son seq<seq<int>> objetos. Cada secuencia (tanto interna como externa) puede tener cualquier cantidad de elementos.

+0

Entonces, ¿quieres hacer una transposición matricial o agrupar por un elemento; esto no es muy claro. Un ejemplo para una entrada más larga sería bueno. –

+1

posible duplicado de [¿Cómo escribo una función tipo ZipN en F #?] (Http://stackoverflow.com/questions/11770441/how-do-i-write-a-zipn-like-function-in-f) – Daniel

Respuesta

3

Si busca una solución semánticamente Seq, tendrá que permanecer flojo todo el tiempo.

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 

prueba:

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

Salida:

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

mientras esto funcione, Seq.groupBy no es flojo y evaluará completamente sus secuencias de entrada una vez que se solicite el primer elemento desde Seq.groupBy –

1

esto parece muy poco elegante, pero tiene la respuesta correcta:

(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

Parece prometedor, pero ¿cómo convierto seq > a seq para usar este método? – bytebuster

+0

La pregunta de OP requiere que la solución opere en una secuencia de secuencias de longitud variable, y no una secuencia de n-tuplas. – Asti

0

Parece que la transposición de la matriz.

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 

Alternativamente, puede adoptar el mismo método para seq, gracias a this answer de un elegante patrón activo:

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 

Véase también this answer para los detalles técnicos y dos referencias: a PowerPack 's Microsoft.FSharp.Math.Matrix y otro método más que implica datos mutables.

+0

Esto evalúa todas las secuencias con impaciencia. 'Seq.ofList' no hace más que lanzar la lista a' seq <'t> ', por lo que no tiene mucho sentido tener la firma como 'seq >'. – Asti

0

Ésta es la misma respuesta que @Asti, acaba de limpiar un poco:

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