Week 7: Explanation for exercise 6.1 (Symmetric Difference of Lists)

Subsite home page:
 http://bit.ly/focs-aux

Exercise 6.1

Implement the function diff which computes the symmetric difference of two lists, which means collecting all of the elements that appear only in one of the lists. The order of the remaining elements should stay unchanged. Remember we are interested in collecting elements that appear exactly in one of the lists. In particular, elements that appear in both lists l1 and l2 should not be in diff l1 l2 .

Example:

l1 = [1;2;3;2;3]

l2 = [3;4;3]

diff l1 l2 = [1;2;2;4]

We do this exercise in three steps:

First step:

First we define a function called subdif that takes a list and an entry and returns a list with all elements different than the given entry

subdif: 'a list -> 'a -> 'a list

Let’s see how subdif works

subdif [1;2;3;2;3] 3 =
1 :: subdif [2;3;2;3] 3 =
1 :: 2 :: subdif [3;2;3] 3 =
1 :: 2 :: subdif [2;3] 3 =
1 :: 2 :: 2 :: subdif [3] 3 =
1 :: 2 :: 2 :: [] =
[1;2;2]

And this is how we define the function subdif

Let rec subdif l ent = match l with
                      | [] -> []
                      | x :: xs ->
                        if (x = ent) then subdif xs ent
                        else x :: subdif xs ent

Second step:

In the second step, we define another function which we call prediff. We expect this function to take two lists l1 and l2 and return all of elements in l1 which are not in l2. Note that this function is not symmetric with respect to the two lists l1 and l2. So, this cannot be our final answer.

The type of this function would then be

predif: 'a list -> ' a list -> 'a list

And the function itself is

Let rec predif l1 l2 = match l2 with
                   | [] -> l1
                   | x ::xs -> predif (subdif l1 x) xs ;;

Now let’s look at some computation done with the function we just defined

predif [1;2;3;2;3] [3;4;3] =
predif (subdif [1;2;3;2;3] 3) [4;3] =
predif [1;2;2] [4;3] =
predif (subdif [1;2;2] 4) [3] =
predif ([1;2;2]) [3] =
predif (subdif [1;2;2] 3) [] =
predif [1;2;2] [] =
[1;2;2]

Final step:

Now finally we can define symmetric difference function diff.

It has the type

diff: 'a list -> 'a list -> 'a list

And the function itself

Let rec subdif l ent = match l with
                    | [] -> []
                    | x :: xs ->
                      if (x = ent) then subdif xs ent
                      else x :: subdif xs ent


Let rec predif l1 l2 = match l2 with
                    | [] -> l1
                    | x ::xs -> predif (subdif l1 x) xs



Let rec diff l1 l2 = append (predif l1 l2) (predif l2 l1) ;;

A set theoretical remark:

It’s hard to not notice that our definition of symmetric difference of lists is analogous to of symmetric difference of sets, except that the case of sets is even simpler because we don’t care about maintaining the order while we are taking the difference.

In other words, since sets do not have order structure, there is nothing to be checked about order preservation.

For symmetric difference of sets look at: https://en.wikipedia.org/wiki/Symmetric_difference

A different and shorter solution:

Remark: There is a library function val filter which you might find useful in order to come up with another solution for this exercise:

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.

The following function computes symmetric difference

let predif xs ys = filter (fun x -> not (mem x ys)) xs

where

val mem : 'a -> 'a list -> bool
mem a l is true if and only if a is equal to an element of l.