2010-07-08 13 views
9

Supongamos que tengo un poco de código como este:¿Cómo puedo omitir un término con List.Map en OCAML?

List.map (fun e -> if (e <> 1) then e + 1 else (*add nothing to the list*)) 

¿Hay una manera de hacer esto? ¿Si es así, cómo?

Quiero manipular el elemento si coincide con algunos criterios e ignorarlo si no lo hace. Por lo tanto, List.filter no parece ser la solución.

Respuesta

12

SML tiene una función mapPartial que hace exactamente esto. Lamentablemente, esta función no existe en OCaml. Sin embargo, puede definir fácilmente por sí mismo de esta manera:

let map_partial f xs = 
    let prepend_option x xs = match x with 
    | None -> xs 
    | Some x -> x :: xs in 
    List.rev (List.fold_left (fun acc x -> prepend_option (f x) acc) [] xs) 

Uso:

map_partial (fun x -> if x <> 1 then Some (x+1) else None) [0;1;2;3] 

volverá [1;3;4].

O puede usar filter_map from extlib como señaló ygrek.

+6

List.filter_map en extlib – ygrek

4

alternativa, se puede filtrar la lista a continuación, aplicar el mapa en la lista como resultado de la siguiente manera:

let map_bis predicate map_function lst = 
    List.map map_function (List.filter predicate lst);; 

# val map_bis : ('a -> bool) -> ('a -> 'b) -> 'a list -> 'b list = <fun> 

Uso:

# map_bis (fun e -> e<>1) (fun e -> e+1) [0;1;2;3];; 
- : int list = [1; 3; 4] 
7

Tanto Batteries y Extlib proporcionar un equivalente de mapPartial: su extendida List El módulo proporciona una función filter_map del tipo ('a -> 'b option) -> 'a list -> 'b list, lo que permite que la función de mapa también seleccione elementos.

5

Otra solución sería utilizar directamente un foldl:

let f e l = if (e <> 1) 
      then (e + 1)::l 
      else l 
in List.fold_left f [] list 

Pero mi preferencia es filter_map como Michael E

1

También puede asignar valores a Singleton listas si quieres mantenerlos o listas vacías si no lo hace, y luego concat los resultados.

List.concat (List.map (fun e -> if (e <> 1) then [e + 1] else []) my_list) 
Cuestiones relacionadas