tutorial que ejemplos curso compilador acorde .net f#

.net - que - f# tutorial



Producto cruzado de dos listas (5)

Juguetón con ''funciones de extensión'' para el módulo de la Lista. (Pasé bastante tiempo desarrollando ''mapfold'', que enlaza un acumulador como fold, pero lo usa como parámetro para crear nuevos valores como map, y luego descubrí que eso es lo que hace List.scan_left )

Para la generación de datos de prueba, tuve que hacer un producto cruzado de dos listas. Esto es lo que se me ocurrió:

///Perform cross product of two lists, return tuple let crossproduct l1 l2 = let product lst v2 = List.map (fun v1 -> (v1, v2)) lst List.map_concat (product l1) l2

¿Esto es bueno o hay alguna forma mejor de hacerlo?

La misma pregunta para este:

///Perform cross product of three lists, return tuple let crossproduct3 l1 l2 l3 = let tuplelist = crossproduct l1 l2 //not sure this is the best way... let product3 lst2 v3 = List.map (fun (v1, v2) -> (v1, v2, v3)) lst2 List.map_concat (product3 tuplelist) l3


Otra opción es usar F # "expresiones de secuencia" y escribir algo como esto:

let crossproduct l1 l2 = seq { for el1 in l1 do for el2 in l2 do yield el1, el2 };;

(en realidad, es casi lo mismo que lo que escribiste, porque ''para ... en .. do'' en la expresión de secuencia se puede ver como map_concat). Esto funciona con secuencias (flojas), pero si quieres trabajar con listas, simplemente envolverías el código dentro [...] en lugar de dentro de la secuencia {...}.


Su función de productos cruzados se ve bien (probablemente haya notado las palabras clave "in" que faltan). Me gusta más esta versión de crossproduct3, pero así soy yo:

let crossproduct3 l1 l2 l3 = List.map_concat (fun z -> (List.map_concat (fun y -> List.map (fun x -> (x, y, z)) l3) l2)) l1;;

Tu función tiene una complejidad algorítmica equivalente.

Finalmente, al usar crossproduct en una lista explícitamente vacía , puede presionar sobre la restricción de valor (más o menos, una restricción que asegura que el compilador solo infiere tipos polimórficos para un valor sintáctico), que es particularmente estricto en F #. La solución es anotar llamadas que usan una lista vacía, de la siguiente manera (si desea que la segunda lista esté compuesta de números enteros):

(crossproduct [3; 4] [] : (int * int) list)


Recientemente necesité algo similar: tuve que comprimir una lista de secuencias en una secuencia de listas, entonces [(a1,a2,a3,...);(b1,b2,b3,...);(c1,c2,c3,...)] -> ([a1;b1;c1], [a2;b2;c3], ...)

El siguiente código hará esto:

let rec listZip (sl : ''a seq list) = seq { match sl with | [] -> yield [] | hd::tl -> for h in hd do for t in listZip tl do yield (h::t) }


Acabo de encontrar una solución bastante elegante para esto usando expresiones de cálculo:

type Product () = member this.Bind (l,f) = List.collect f l member this.Return n = [n] let enumeratedPizzas = Product() { let! x = ["New York";"Chicago"] let! y = ["Pepperoni";"Sausage"] let! z = ["Cheese";"Double Cheese"] return x,y,z }

Por Techneilogy , copiado de fssnip.net , sigue el enlace para ver el código comentado.


Estuve usando la respuesta de Benjol por un tiempo hasta que descubrí que puedes hacer casi lo mismo con Linq . La solución de Benjol es probablemente la más elegante, pero si alguien quiere una solución que pueda usar con C# , entonces aquí tiene:

query { for i in [1, 2] do for j in [3, 4] do select (i, j) }

Lo cual es casi exactamente lo mismo que la solución de Tomas Petricek, excepto que la solución no necesita estar anidada for bucles, por lo que es un poco más simple.