Difference between list.map and list.collect - collections

What is the difference between map and collect? documentation below - i cant tell the difference..
List.map<'T,'U> Function
Creates a new collection whose elements are the results of applying the given function to each of the elements of the collection.
// Signature:
List.map : ('T -> 'U) -> 'T list -> 'U list
List.collect<'T,'U> Function
For each element of the list, applies the given function. Concatenates all the results and returns the combined list.

An example for illustration
Let's say you have a list of lists:
let list = [ [1; 2]; [3; 4]; [5; 6] ]
And a transformation function:
let trans = fun x -> [for i in x -> i*10]
List.map trans list will produce:
[[10; 20]; [30; 40]; [50; 60]]
While
List.collect trans list will produce:
[10; 20; 30; 40; 50; 60]
List.collect will apply the transformation function and will Concatenate the result while List.map will only apply the transformation function.

The difference is that the output list from map is the same length as the input list. For collect, the output list may be longer or shorter than the input as the function you pass returns a list instead of a single element.
For more detail - compare the signatures. For map
List.map : ('T -> 'U) -> 'T list -> 'U list
and collect
List.collect : ('T -> 'U list) -> 'T list -> 'U list
you can see here that the return type of the function argument is different.

Adding to #John's answer, the difference is in the word Concatenates.
Basically, List.collect f xs is the same as List.concat (List.map f xs).

Related

What does the h :: t pattern matching means in OCaml?

I'm reading https://ocaml.org/learn/tutorials/99problems.html and it has 2 examples:
# let rec last_two = function
| [] | [_] -> None
| [x;y] -> Some (x,y)
| _::t -> last_two t;;
I understand the first one: _::t means pattern match anything and call it t
But at
# let rec at k = function
| [] -> None
| h :: t -> if k = 1 then Some h else at (k-1) t;;
I don't understand what h means. For me it should be _:: t -> ... to match anything and call it t
The pattern _ :: t doesn't mean what you say. It matches any non-empty list and calls the tail of the list t.
The pattern h :: t matches any non-empty list, calls the head of the list h (one element, the first one), and the tail of the list t (zero or more elements after the first one).
The operator :: is the list constructor (often called "cons"), which is why these patterns match lists.
Here are examples of :: as list constructor:
# true :: [];;
- : bool list = [true]
# 1 :: [2; 3];;
- : int list = [1; 2; 3]
As is usual in OCaml, the pattern for a list uses the same syntax as the constructor.
# match [1;2;3] with [] -> None | h :: t -> Some (h, t);;
- : (int * int list) option = Some (1, [2; 3])
The h::t pattern matches the head and tail of the list to the variables h and t.
So if I pattern match like this:
match [1; 2; 3] with
| h::t -> (* Some code... *)
h will have a value of 1, and t will have the value of [2; 3].
:: is a constructor. Pattern matching in this fashion pattern matches against constructors. They create a new datatype out of two values. :: is a constructor, and its type, list, is recursive. Here's a sample definition of the list type:
type 'a list =
| []
| (::) 'a * ('a list)
;;
So the list type is recursive because its constructor, ::, calls itself.
Honestly, I could write half a book on lists. They're the bread and butter of functional programming languages.
If you're wondering why you can't pattern match on operators, this is why. You can't pattern match on operators, only constructors.
Yes, indeed when you type in a function let's take for example this one:
let is_empty (l: int list) : int =
begin match l with
| [] -> 1
| h::t -> 0
end;;
Therefore, in this function that tests if a list is empty or not, if [], an empty list it returns one or in boolean true but if h::t, meaning that there is one or more value, the function returns 0, meaning it's false.

List Recursion in Ocaml

This is what I want to achive, to return to a list with values that are below the given value with recursion:
# list_below 3 [7; 1; 0; 3];;
- : int list = [1; 0]
# list_below 1 [-7; 1; 0; 3];;
- : int list = [-7; 0]
# list_below 9.0 [4.2; 3.6; 5.0; 12.8];;
- : float list = [4.2; 3.6; 5.0]
Here is what I wrote so far, and it does not appear to return anything.
let rec list_below thresh lst =
if List.hd lst > thresh then [] else
List.hd lst :: list_below thresh (List.tl lst);;
;;
Could you show me what is wrong with my code?
The problem should be what Jeffrey has pointed out for you.
Your questions says you want to implement list_below, but your code shows list_above. I'll stick to list_below here.
Recursive functions in Ocaml can be made quite intuitively if you use pattern matching. For example, the below code should work :
let rec list_below thresh lst =
match lst with
| [] -> []
| hd :: tl -> if hd < thresh then hd :: (list_below thresh tl)
else list_below thresh tl;;
If the first value is above the threshhold your code always returns an empty list. That can't be right. It is inconsistent with your first example, for one thing.
You could try using List.filter. Since you want to get a list of values that are less than the supplied value, then filter should do what you want.
Here's the documentation for filter:
val filter : ('a -> bool) -> 'a list -> 'a list
filter p l returns all the elements of the list l that satisfy the predicate p. The order of the elements in the input list is preserved.
What you need is to provide a predicate p. A predicate is a function that takes an element and returns a boolean. Filter will take this predicate and apply to each value in the list. If the predicate returns true for that element, the element will be added to the resulting list.
So in your case, list_below should be
let list_below thresh lst =
List.filter (fun elem -> elem < thresh) lst
More more operations on list, check out this chapter in Real World OCaml.

F# adding lists

How would I go about adding sub-lists.
For example, [ [10;2;10]; [10;50;10]] ----> [20;52;20] that is 10+10, 2+50 and 10+10. Not sure how to start this.
Fold is a higher order function:
let input = [[10;2;10]; [10;50;10]]
input |> Seq.fold (fun acc elem -> acc + (List.nth elem 1)) 0
val it : int = 52
Solution 1: Recursive version
We need a helper function to add two lists by summing elements one-to-one. It is recursive and assumes that both lists are of the same length:
let rec sum2Lists (l1:List<int>) (l2:List<int>) =
match (l1,l2) with
| ([],[]) -> []
| (x1::t1, x2::t2) -> (x1+x2)::sum2Lists t1 t2
Then the following recursive function can process a list of lists, using our helper function :
let rec sumLists xs =
match xs with
| [] -> [] // empty list
| x1::[] -> x1 // a single sublist
| xh::xt -> sum2Lists xh (sumLists xt) // add the head to recursion on tail
let myres = sumLists mylist
Solution 2: higher order function
Our helper function can be simplified, using List.map2:
let sum2hfLists (l1:List<int>) (l2:List<int>) = List.map2 (+) l1 l2
We can then use List.fold to create an on the flow accumulator using our helper function:
let sumhfList (l:List<List<int>>) =
match l with
| [] -> [] // empty list of sublist
| h::[] -> h // list with a single sublist
| h::t -> List.fold (fun a x -> sum2hfLists a x) h t
The last match case is applied only for lists of at least two sublists. The trick is to take the first sublist as starting point of the accumulator, and let fold execute on the rest of the list.

Map a list of options to list of strings

I have the following function in OCaml:
let get_all_parents lst =
List.map (fun (name,opt) -> opt) lst
That maps my big list with (name, opt) to just a list of opt. An option can contain of either None or Some value which in this case is a string. I want a list of strings with all my values.
I am a beginner learning OCaml.
I don't think filter and map used together is a good solution to this problem. This is because when you apply map to convert your string option to string, you will have the None case to deal with. Even if you know that you won't have any Nones because you filtered them away, the type checker doesn't, and can't help you. If you have non-exhaustive pattern match warnings enabled, you will get them, or you will have to supply some kind of dummy string for the None case. And, you will have to hope you don't introduce errors when refactoring later, or else write test cases or do more code review.
Instead, you need a function filter_map : ('a -> 'b option) -> 'a list -> 'b list. The idea is that this works like map, except filter_map f lst drops each element of lst for which f evaluates to None. If f evaluates to Some v, the result list will have v. You could then use filter_map like so:
filter_map (fun (_, opt) -> opt) lst
You could also write that as
filter_map snd lst
A more general example would be:
filter_map (fun (_, opt) ->
match opt with
| Some s -> Some (s ^ "\n")
| None -> None)
lst
filter_map can be implemented like this:
let filter_map f lst =
let rec loop acc = function
| [] -> List.rev acc
| v::lst' ->
match f v with
| None -> loop acc lst'
| Some v' -> loop (v'::acc) lst'
in
loop [] lst
EDIT For greater completeness, you could also do
let filter_map f lst =
List.fold_left (fun acc v ->
match f v with
| Some v' -> v'::acc
| None -> acc) [] lst
|> List.rev
It's a shame that this kind of function isn't in the standard library. It's present in both Batteries Included and Jane Street Core.
I'm going to expand on #Carsten's answer. He is pointing you the right direction.
It's not clear what question you're asking. For example, I'm not sure why you're telling us about your function get_all_parents. Possibly this function was your attempt to get the answer you want, and that it's not quite working for you. Or maybe you're happy with this function, but you want to do some further processing on its results?
Either way, List.map can't do the whole job because it always returns a list of the same length as its input. But you need a list that can be different lengths, depending on how many None values there are in the big list.
So you need a function that can extract only the parts of a list that you're interested in. As #Carsten says, the key function for this is List.filter.
Some combination of map and filter will definitely do what you want. Or you can just use fold, which has the power of both map and filter. Or you can write your own recursive function that does all the work.
Update
Maybe your problem is in extracting the string from a string option. The "nice" way to do this is to provide a default value to use when the option is None:
let get default xo =
match xo with
| None -> default
| Some x -> x
# get "none" (Some "abc");;
- : string = "abc"
# get "none" None;;
- : string = "none"
#
type opt = Some of string | None
List.fold_left (fun lres -> function
(name,Some value) -> value::lres
| (name,None) -> lres
) [] [("s1",None);("s2",Some "s2bis")]
result:
- : string list = ["s2bis"]

Writing a function that is sum of functions

I have the following excercise to do:
Code a function that will be a summation of a list of functions.
So I think that means that if a function get list of functions [f(x);g(x);h(x);...] it must return a function that is f(x)+g(x)+h(x)+...
I'm trying to do code that up for the general case and here's something I came up with:
let f_sum (h::t) = fold_left (fun a h -> (fun x -> (h x) + (a x))) h t;;
The problem is I'm using "+" operator and that means it works only when in list we have functions of type
'a -> int
So, can it be done more "generally", I mean can we write a function, that is a sum of ('a -> 'b) functions, given in a list?
yes, you can make plus function to be a parameter of your function, like
let f_sum plus fs =
let (+) = plus in
match fs with
| [] -> invalid_arg "f_sum: empty list"
| f :: fs -> fold_left ...
You can generalize even more, and ask a user to provide a zero value, so that you can return a function, returning zero if the list is empty. Also you can use records to group functions, or even first class modules (cf., Commutative_group.S in Core library).

Resources