Ordenar una lista en diferentes bolsas según el predicado -- beginner campo con f# camp codereview Relacionados El problema

Sorting a list into different bags according to predicate


2
vote

problema

Español

Acabo de empezar con F # (voy de un fondo en su mayoría OO) y estoy buscando

  • comentarios sobre el código, en particular: ¿es así como se debe escribir el código F #?
  • ¿He pasado por alto una función de la biblioteca existente que lo haría más fácil o podría reemplazarlo por completo?

El objetivo es:

Tome una lista de entrada y ordena de acuerdo con ciertas condiciones en varias bolsas, manteniendo también aquellos artículos que no se ajusten a ninguna condición. (Por eso groupBy no hace el truco, a menos que esté pasando por alto algo).

La función:

  let sortIntoBags<'T, 'TBag> (predicate: 'TBag*'T->bool) (bags: 'TBag list)  (lst: 'T list)=     let take (lst: 'T list) (bag: 'TBag)=         let isInBag e = predicate (bag, e)         let (inBag, remaining) = lst |> List.partition isInBag         ((bag, inBag), remaining)     let (bagSets, leftOver) = bags |> List.mapFold take lst     (bagSets, leftOver)   

Un ejemplo simple para el uso es:

  > let l= [1..25];;  val l : int list = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 11; 12; 13; 14; 15; 16; 17; 18; 19; 20; 21;  22; 23; 24; 25]  > let bags= [2; 3; 5; 7];; val bags : int list = [2; 3; 5; 7]  > let isDivisorFor (x, y) = 0=y%x ;; val isDivisorFor : x:int * y:int -> bool  > l |> sortIntoBags isDivisorFor bags;; val it : (int * int list) list * int list = ([(2, [2; 4; 6; 8; 10; 12; 14; 16; 18; 20; 22; 24]); (3, [3; 9; 15; 21]); (5, [5; 25]); (7, [7])], [1; 11; 13; 17; 19; 23])   
Original en ingles

I've just started with F# (I'm coming from a mostly OO background) and I'm looking for

  • feedback on the code, particularly: is this the way F# code should be written like?
  • have I overlooked an existing library function which would make this easier or could replace it completely?

The goal is:

Take an input list and sort it according to certain conditions into several bags, keeping also those items not fitting any condition. (Which is why groupBy doesn't do the trick, unless I'm overlooking something).

The function:

let sortIntoBags<'T, 'TBag> (predicate: 'TBag*'T->bool) (bags: 'TBag list)  (lst: 'T list)=     let take (lst: 'T list) (bag: 'TBag)=         let isInBag e = predicate (bag, e)         let (inBag, remaining) = lst |> List.partition isInBag         ((bag, inBag), remaining)     let (bagSets, leftOver) = bags |> List.mapFold take lst     (bagSets, leftOver) 

A simple example for usage is:

> let l= [1..25];;  val l : int list = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 11; 12; 13; 14; 15; 16; 17; 18; 19; 20; 21;  22; 23; 24; 25]  > let bags= [2; 3; 5; 7];; val bags : int list = [2; 3; 5; 7]  > let isDivisorFor (x, y) = 0=y%x ;; val isDivisorFor : x:int * y:int -> bool  > l |> sortIntoBags isDivisorFor bags;; val it : (int * int list) list * int list = ([(2, [2; 4; 6; 8; 10; 12; 14; 16; 18; 20; 22; 24]); (3, [3; 9; 15; 21]); (5, [5; 25]); (7, [7])], [1; 11; 13; 17; 19; 23]) 
     
       
       

Lista de respuestas

1
 
vote
vote
La mejor respuesta
 

Me gusta su uso de List.partition pero tengo la siguiente sugerencia:

Si es posible en el contexto, evite hacer los argumentos como una tupla en el predicado. Simplemente declararlo como:

  let isDivisorFor div x = x % div = 0    

nb: Utilizo esta versión en todas las versiones a continuación

Hará que IMO lo hará más legible:

  let sortIntoBags predicate bags lst =     let take lst bag =         let (inBag, remaining) = lst |> List.partition (predicate bag)         ((bag, inBag), remaining)     let (bagSets, leftOver) = bags |> List.mapFold take lst     (bagSets, leftOver)   

      let (bagSets, leftOver) = bags |> List.mapFold take lst     (bagSets, leftOver)   

Aquí no hay necesidad de la última línea. Solo devuelve el lado derecho de la primera línea: haciéndolo un poco más simple:

  let sortIntoBags predicate bags lst =     let take lst bag =         let (inBag, remaining) = lst |> List.partition (predicate bag)         ((bag, inBag), remaining)     bags |> List.mapFold take lst   

Solo por diversión, hice una versión usando la recursión:

  let sortIntoBags predicate bags data =     let rec part lst bgs result =         match bgs with         | [] -> result |> List.rev, lst         | _ -> let group, remaing = lst |> List.partition (predicate bgs.Head)                (part remaing bgs.Tail ((bgs.Head, group)::result))     part data bags []   

Observe que tengo el resultado total como argumento a la función part para hacerlo recursivo de la cola.


Si puede vivir con un valor 9988776655544337 List.groupBy :

  let sortIntoBags predicate bags data =     data |> List.groupBy (fun x -> bags |> List.tryFind (fun k -> predicate k x))   

... Si no, se hace un poco más complicado y, entonces, usted puede ser una mejor opción:

  let isDivisorFor div x = x % div = 0  0  

o con el uso de let isDivisorFor div x = x % div = 0 1 :

  let isDivisorFor div x = x % div = 0  2  
 

I like your use of List.partition but I have the following suggestion:

If it's possible in the context then avoid making the arguments as a tuple in the predicate. Just declare it as:

let isDivisorFor div x = x % div = 0  

NB: I use this version in all versions below

It will IMO make it all more readable:

let sortIntoBags predicate bags lst =     let take lst bag =         let (inBag, remaining) = lst |> List.partition (predicate bag)         ((bag, inBag), remaining)     let (bagSets, leftOver) = bags |> List.mapFold take lst     (bagSets, leftOver) 

    let (bagSets, leftOver) = bags |> List.mapFold take lst     (bagSets, leftOver) 

Here there is no need for the last line. Just return the right side of the first line - making it a little more simple:

let sortIntoBags predicate bags lst =     let take lst bag =         let (inBag, remaining) = lst |> List.partition (predicate bag)         ((bag, inBag), remaining)     bags |> List.mapFold take lst 

Just for fun, I made a version using recursion:

let sortIntoBags predicate bags data =     let rec part lst bgs result =         match bgs with         | [] -> result |> List.rev, lst         | _ -> let group, remaing = lst |> List.partition (predicate bgs.Head)                (part remaing bgs.Tail ((bgs.Head, group)::result))     part data bags [] 

Notice that I have the total result as argument to the part function in order to make it tail-recursive.


If you can live with an Option value as the group key, it is fairly simple to use List.groupBy:

let sortIntoBags predicate bags data =     data |> List.groupBy (fun x -> bags |> List.tryFind (fun k -> predicate k x)) 

... If not it gets a little more complicated and then your own may be a better choise:

let sortIntoBags predicate bags data =     let result = data |> List.groupBy (fun x -> bags |> List.tryFind (fun k -> predicate k x))     (result |> List.where (fun (k, l) -> k.IsSome) |> List.map (fun (k, l) -> k.Value, l), result |> List.where (fun (k, l) -> k.IsNone) |> List.head |> snd) 

or with the use of List.partition:

let sortIntoBags predicate bags data =     let result = data |> List.groupBy (fun x -> bags |> List.tryFind (fun k -> predicate k x)) |> List.partition (fun (k, l) -> k.IsSome)     (fst result |> List.map (fun (k, l) -> k.Value, l), (snd result |> List.head |> snd)) 
 
 
 
 
2
 
vote

Aquí hay otra forma (subjetivamente mejor o peor) de escribir esto, sin embargo, requiere una comparación a diferencia de la suya:

  let isDivisorFor div x = x % div = 0  3  

y las pruebas XUNIT que solía asegurarme de que coincidiera con la salida

  let isDivisorFor div x = x % div = 0  4  
 

Here's another (Subjectively better or worse) way to write this, however it does require comparison unlike yours:

let sortIntoBags<'T,'TKey when 'TKey : comparison > (predicate:'TKey*'T -> bool) (bagKeys:'TKey list) (items:'T list) : ('TKey*'T list) list * 'T list =     let bagMap:Map<'TKey,'T list> = bagKeys |> Seq.map(fun k -> k,List.empty) |> Map.ofSeq     items     |> List.rev     |> List.fold(fun (bagMap,unmatched:'T list) (item:'T) ->         match bagMap |> Map.tryFindKey(fun k _ -> predicate(k,item)) with         | Some k -> bagMap |> Map.add k (item::bagMap.[k]), unmatched         | None -> bagMap,item::unmatched      ) (bagMap,List.empty)     |> fun (m,x)->         m |> Map.toList, x 

and the xunit tests I used to make sure it matched the output

open global.Xunit  [<Fact>] let originalQuestion2 () =    let l= [1..25]    let bags= [2; 3; 5; 7]    let isDivisorFor (x, y) = 0=y%x    let expected = [(2, [2; 4; 6; 8; 10; 12; 14; 16; 18; 20; 22; 24]); (3, [3; 9; 15; 21]);(5, [5; 25]); (7, [7])], [1; 11; 13; 17; 19; 23]    let actual = l |> BagSort.sortIntoBags isDivisorFor bags    printfn "%A" actual    Console.Error.WriteLine(sprintf "%A" actual)    Trace.WriteLine(sprintf "%A" actual)    Assert.Equal(expected, actual)   [<Fact>] let originalQuestionUnfolded2 () =    let l= [1..25]    let bags= [2; 3; 5; 7]    let isDivisorFor (x, y) = 0=y%x    let expected =         let a =             [   2, [2; 4; 6; 8; 10; 12; 14; 16; 18; 20; 22; 24]                 3, [3; 9; 15; 21]                 5, [5; 25]                 7, [7]             ]         let b = [1; 11; 13; 17; 19; 23]         a,b    let actual = l |> BagSort.sortIntoBags isDivisorFor bags    Assert.Equal(expected, actual)    Assert.Equal((fst expected |> fun x -> x.[0]), fst actual |> fun x -> x.[0]) 
 
 
         
         

Relacionados problema

3  Convertir el valor de bitcoin basado en el tipo de cambio de JSON API  ( Convert bitcoin value based on exchange rate from json api ) 
Estoy aprendiendo F # e intentando encontrar una forma más 'funcional' de codificar un programa simple que recupera el precio de BTC y calcula el valor del EU...

2  Usando tipos en F #  ( Using types in f ) 
He jugado con F # por más de un año, pero recientemente he comenzado tentativamente lo usándolo para el trabajo profesional. Me preocupa que mis principios de...

4  Clases de datos puros inmutables con artículos públicos en propiedades  ( Immutable pure data classes with public setters on properties ) 
Estoy reuniendo algunas clases como modelo para alguna información (que actualmente estoy tirando de un sitio web). Las clases se implementan en C #, porque...

4  ¿Cómo refactorizar este método de Groupby por igual pero con el índice?  ( How to refactor this groupby alike method but with index ) 
Tengo una matriz jaggada 2D (la fila es la primera dimensión, la columna es la segunda dimensión, la parte inferior de la derecha, de izquierda a derecha) ...

9  Eliminación de árbol negro rojo en F #  ( Deleting from red black tree in f ) 
Sí, estoy muy lentamente a través de las estructuras de datos puramente funcionales. Así que pasé por la sección sobre árboles negros rojos. Lo que presenta e...

10  Obteniendo la última fecha donde ocurrió un día de la semana dado  ( Getting the last date where a given week day occurred ) 
Estoy tratando de aprender un poco sobre la programación funcional y como mi herramienta, elegí F # ya que soy un desarrollador de .NET y el medio ambiente es...

3  Mi implementación de permutación lexicográfica en F # es 3x más lenta que C #  ( My implementation of lexicographic permutation in f is 3x slower than c ) 
¿Puede alguien ayudarme con la siguiente micro optimización para el código F # para la permutación lexicográfica? Tengo código en C # que se ejecuta para 0,...

2  F # Patrón activo con póquer y naipes  ( F active pattern with poker and playing cards ) 
de Esta pregunta y John Palmers responden Sobre el patrón activo Descubrí una brecha en mi conocimiento sobre F # y tomé el desafío de codificarme en algún ...

13  Poker Hands Kata en F #  ( Poker hands kata in f ) 
Soy un F # Newbie, y me gustaría compartir mi implementación de la Poker Hands Kata Problem Para obtener algunos comentarios. string1 En la primera mi...

11  Enfoque para construir programáticamente componentes gui jerárquicos  ( Approach to programmatically building hierarchical gui components ) 
En el trabajo, estoy desarrollando una aplicación usando el swing codificado a mano, y he encontrado que tengo un tiempo más fácil de leer, escribir y mantene...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos