Как я могу пропустить термин с List.Map в OCAML? - PullRequest
10 голосов
/ 08 июля 2010

Предположим, у меня есть такой код:

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

Есть ли способ сделать это? Если да, то как?

Я хочу манипулировать элементом, если он соответствует некоторым критериям, и игнорировать его, если это не так. Таким образом, List.filter, похоже, не является решением.

Ответы [ 5 ]

13 голосов
/ 08 июля 2010

SML имеет функцию mapPartial, которая делает именно это. К сожалению, эта функция не существует в OCaml. Однако вы можете легко определить это так:

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)

Использование:

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

вернет [1;3;4].

Или вы можете использовать filter_map из extlib , как указал Игрек.

7 голосов
/ 09 июля 2010

Обе Батареи и Extlib обеспечивают эквивалент mapPartial: их расширенный модуль List обладает функцией filter_map типа ('a -> 'b option) -> 'a list -> 'b list, что позволяет использовать функцию карты чтобы выбрать элементы.

5 голосов
/ 21 июня 2011

Другое решение - использовать foldl:

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

Но я предпочитаю filter_map как Майкл E

4 голосов
/ 08 июля 2010

В качестве альтернативы вы можете отфильтровать свой список, а затем применить карту к полученному списку следующим образом:

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>

Использование:

# map_bis (fun e -> e<>1) (fun e -> e+1) [0;1;2;3];;
- : int list = [1; 3; 4]
1 голос
/ 13 сентября 2011

Вы также можете отобразить значения в одноэлементные списки, если вы хотите сохранить их, или пустые списки, если вы этого не сделаете, и затем объединить результаты.

List.concat (List.map (fun e -> if (e <> 1) then [e + 1] else []) my_list)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...