2

Let's say we have two lists, [3;4;5] and [1;2;3], how can I get the distance of 12, which is found by subtracting the second list from the first, and squaring. So (3-1)^2 + (4-2)^2 + (5-3)^2. I currently have this to square it:

List.map (List.map (fun x -> x*x)) [[1; 2]; [2; 3]];;

But how can I get it to subtract and add them all together? The above sequence only returns [[1;4];[4;9]].

Thanks.

Francis
  • 23
  • 3
  • Presumably OCaml has a zip function. Zip the lists to a list of ordered pairs, map subtraction across then map square then sum the result. – John Coleman Jul 27 '15 at 23:05
  • @JohnColeman No zip function in stdlib, the stdlib is really small. –  Jul 28 '15 at 00:22
  • @EdgarAroutiounian That's odd. I always vaguely thought of O'Caml as being ML + objects. With SML the problem is fairly trivial. – John Coleman Jul 28 '15 at 00:34
  • 1
    `zip` is called `List.combine` in OCaml. However, rather than constructing an intermediate list you would probably just use `List.map2` (or `List.fold2`). – gsg Jul 28 '15 at 11:12

4 Answers4

2

The result of List.map is a list, so you have to reduce it to an integer. The simple way to do this with the library is to use List.fold_left.

# let distance a b = List.fold_left (fun s -> fun x -> s + x * x) 0 (List.map2 (-) a  b);;
val distance : int list -> int list -> int = <fun>
# distance [3; 4; 5] [1; 2; 3];;
- : int = 12

Be sure that the lengths of the lists are equal, otherwise List.map2 raises an exception.

# distance [3; 4] [1; 2; 3];;
Exception: Invalid_argument "List.map2".
dawns
  • 91
  • 4
1

Borrowing this integer exponentiation function from:Integer exponentiation in OCaml

let rec pow a = function
  | 0 -> 1
  | 1 -> a
  | n ->
    let b = pow a (n / 2) in
    b * b * (if n mod 2 = 0 then 1 else a)

let rec distance l r =
  match l, r with
  | a_val_l :: rest_l, a_val_r :: rest_r -> pow (a_val_l - a_val_r) 2 + distance rest_l rest_r
  | _ -> 0

Your example:

utop[58]> distance [3;4;5] [1;2;3];;
- : int = 12
Community
  • 1
  • 1
  • Knowing you only use it with 2, `pow` is a bit overkill, a `square` function would be enough. – PatJ Jul 28 '15 at 08:21
0

You can fold over 2 lists:

let distance = List.fold_left2 (fun s x y -> s + (x - y) * (x - y)) 0

Jürgen Hötzel
  • 18,997
  • 3
  • 42
  • 58
0

To get the differences:

let difs = List.map2 (fun a b -> a - b) [3;4;5] [1;2;3]

To square those:

let difs' = List.map (fun x -> x * x) difs

To get the resulting sum:

let res = List.fold_left (+) 0 difs'

As a function:

let list_dist l1 l2 =
  List.map2 (fun a b -> a - b) l1 l2
  |> List.map (fun x -> x * x)
  |> List.fold_left (+) 0
chrismamo1
  • 917
  • 1
  • 7
  • 15