How to build a Map using a list? - list

I have a node type like the following :
type position = float * float
type node = position
I created those modules for the Map :
module MyMap =
struct
type t = node
let compare (a1,b1) (a2,b2) =
if a1 > a2 then 1
else if a1 < a2 then -1
else if b1 > b2 then 1
else if b1 < b2 then -1
else 0
end
module DistMap = Map.Make(MyMap)
I have written this function to add elements to my map.
let init_dist nodes source =
let testMap = DistMap.empty in
let rec init_dist_aux nodes map source =
match nodes with
| [] -> map
| x::tl -> if x = source then map = DistMap.add x 0. map else map = DistMap.add x max_float map;
init_dist_aux tl map source
in init_dist_aux nodes testMap source
The output was :
Characters 160-186:
Warning 10: this expression should have type unit.
val init_dist : node list -> node -> float DistMap.t = <fun>
I tried this :
let initMap = init_dist nodes (4.67521849144109414,6.85329046476252568);;
However init_dist has type unit, so I was unable to create the Map.
My goal is to be able to use this function to build a map.

The error lays in the code below :
match nodes with
| [] -> map
| x::tl -> if x = source then map = DistMap.add x 0. map else map = DistMap.add x max_float map;
init_dist_aux tl map source
Around the 2 pieces of code :
map = DistMap.add...
This is a comparison (and so a boolean) not an assignement as you might wish to implement.
You have to first evaluate map vialet and then process init_dist_aux with new map. Or, since the only difference is the 2nd value (0. or max_float), you can first evaluate this second argument, then process the whole thing as below:
match nodes with
| [] -> map
| x::tl -> let v = if (x = source)
then 0.
else max_float
in
init_dist_aux tl (Dist.add x v map) source

Related

How to build a list using a Map?

First of all, I have those types :
type position = float * float
type node = position
To build my Map I've written those modules :
module MyMap =
struct
type t = Graph.node
let compare (a1,b1) (a2,b2) =
if a1 > a2 then 1
else if a1 < a2 then -1
else if b1 > b2 then 1
else if b1 < b2 then -1
else 0
end
module DistMap = Map.Make(MyMap)
In my case, I'll have a previousMap that has type val previousMap : (float * float) DistMap.t = <abstr>
It contains nodes as key, and values.
Let's say it is built like this :
DistMap.bindings prevMap;;
- : (node * (float * float)) list =
[((1., 1.), (2., 2.));
((2., 2.), (3., 3.));
((3., 3.), (4., 4.));
((4., 4.), (5., 5.))]
It means that (2.,2.) is the predecessor node of (1.,1.) in a graph.
What I am aiming for is to build the list that represent the path from a source node to a target node.
For example, if I had :
let build_path prevMap source target
The expected output using the previousMap would be a node (or float * float) list like this :
build_path previousMap (1.,1.) (5.,5.) -> [(1.,1.);(2.,2.);(3.,3.);(4.,4.);(5.,5.)]
So far my attempts consisted in trying to use the fold and iter function on the previousMap but they were inconclusive.
Update :
Here's an attempt I think could be close to what I want to achieve :
let build_list map source target =
let rec build_aux acc map source x =
if ((DistMap.find x map)) = source then source::acc
else build_aux (DistMap.find x map)::acc source (DistMap.find x map)
in build_aux [] map source target
However I get this error output :
356 | else build_aux (DistMap.find x map)::acc source (DistMap.find x map)
^^^^^^^^^^^^^^^^^^^^
Error: This expression has type 'a but an expression was expected of type
'a list
The type variable 'a occurs inside 'a list
Update 2 :
The issue has been solved, however the function isn't behaving as expected. Basically this is the pseudo-code I'd like to implement :
How could I proceed to build such a list?
Thanks.
The problem with fold and iter is that they process nodes in an order that they determine themselves. In essence the order is based on the shape of the map, which is determined by the keys. You want to process the nodes of the map in an order determined by the values in the map.
I'm pretty sure the only way to proceed is to write your own special-purpose recursive function.
Update
In the latest code you have this expression:
build_aux (DistMap.find x map)::acc source (DistMap.find x map)
The operator precedence in OCaml that binds function arguments to functions is very tight, so this gets parsed like this:
(build_aux (DistMap.find x map)) :: (acc source (DistMap.find x map))
You need parentheses around this subexpression:
((DistMap.find x map)::acc)

How to find the opposite of a number in a list of list in OCaml?

I'm trying to find the opposite of a number in a list of list. I want to iterate through every element of the list of list, and check if the opposite of this element is in the list of list.
This is what I've done so far:
let rec findOpposite l =
match l with
| [] -> false
| f::x::ll -> if (List.mem (-x) f = false && List.mem (-x) ll = false) then true else findOpposite ll;;
I naively assumed 'f' was representing all the previous elements of the list...
I also explored this solution: flatten the list, to make it a bit more simple. But now I'm kinda lost.
What's expected here is to iterate through every element of the list, check if its opposite is in there, if so -> true, otherwise continue until we reach the end.
Thanks.
If this isn't an assignment, I can give one possible solution. If I understand correctly, you want to know if a set of integers is closed under negation. You can calculate the set, then negate the set, then see if the two sets are equal.
module ISet =
Set.Make(struct type t = int let compare = compare end)
let get_set ll =
List.fold_left
(List.fold_left (fun is i -> ISet.add i is))
ISet.empty
ll
let negate_set is = ISet.map (fun i -> -i) is
let closed_set is = ISet.equal is (negate_set is)
You can try it out like this:
# closed_set (get_set [[1;2]; [-2;-2]; [3;-3;-1]]);;
- : bool = true
# closed_set (get_set [[1;2]; [-2;-2]; [3;-3]]);;
- : bool = false

creating a list of lists based on another list content

I have 2 lists. They will always be the same length with respect to each other and might look like this toy example. The actual content is not predictable.
val original = [1, 2, 0, 1, 1, 2]
val elements = ["a","b","c","d","e","f"]
I want to create the following list:
val mappedList = [["c"],["a","d","e"],["b","f"]]
0 1 2
So the pattern is to group elements in the elements list, based on the value of the same-position element in original list. Any idea how can I achieve this in SML? I am not looking for a hard coded solution for this exact data, but a general one.
One way is to first write a function which takes an ordered pair such as (2,"c") and a list of ordered pairs such as
[(3,["a"]),(2,["b"]),(1,["a","e"])]
and returns a modified list with the element tacked onto the appropriate list (or creates a new (key,list) pair if none exists) so that the result would look like:
[(3,["a"]),(2,["c","b"]),(1,["a","e"])]
The following function does the trick:
fun store ((k,v), []) = [(k,[v])]
| store ((k,v), (m,vs)::items) = if k = m
then (m,v::vs)::items
else (m,vs)::store ((k,v) ,items);
Given a list of keys and a corresponding list of values, you could fold this last function over the corresponding zip of the keys and values:
fun group ks vs = foldl store [] (ListPair.zip(ks,vs));
For example, if
val original = [1, 2, 0, 1, 1, 2];
val elements = ["a","b","c","d","e","f"];
- group original elements;
val it = [(1,["e","d","a"]),(2,["f","b"]),(0,["c"])] : (int * string list) list
Note that you could sort this list according to the keys if so desired.
Finally -- if you just want the groups (reversed to match their original order in the list) the following works:
fun groups ks vs = map rev (#2 (ListPair.unzip (group ks vs)));
For example,
- groups original elements;
val it = [["a","d","e"],["b","f"],["c"]] : string list list
On Edit: if you want the final answer to be sorted according to the keys (as opposed to the order in which they appear) you could use #SimonShine 's idea and store the data in sorted order, or you could sort the output of the group function. Somewhat oddly, the SML Standard Basis Library lacks a built-in sort, but the standard implementations have their own sorts (and it is easy enough to write your own). For example, using SML/NJ's sort you could write:
fun sortedGroups ks vs =
let
val g = group ks vs
val s = ListMergeSort.sort (fn ((i,_),(j,_)) => i>j) g
in
map rev (#2 (ListPair.unzip s))
end;
Leading to the expected:
- sortedGroups original elements;
val it = [["c"],["a","d","e"],["b","f"]] : string list list
With the general strategy to first form a list of pairs (k, vs) where k is the value they are grouped by and vs is the elements, one could then extract the elements alone. Since John did this, I'll add two other things you can do:
Assume that original : int list, insert the pairs in sorted order:
fun group ks vs =
let fun insert ((k, v), []) = [(k, [v])]
| insert (k1v as (k1, v), items as ((k2vs as (k2, vs))::rest)) =
case Int.compare (k1, k2) of
LESS => (k1, [v]) :: items
| EQUAL => (k2, v::vs) :: rest
| GREATER => k2vs :: insert (k1v, rest)
fun extract (k, vs) = rev vs
in
map extract (List.foldl insert [] (ListPair.zip (ks, vs)))
end
This produces the same result as your example:
- val mappedList = group original elements;
> val mappedList = [["c"], ["a", "d", "e"], ["b", "f"]] : string list list
I'm a bit unsure if by "The actual content is not predictable." you also mean "The types of original and elements are not known." So:
Assume that original : 'a list and that some cmp : 'a * 'a -> order exists:
fun group cmp ks vs =
let fun insert ((k, v), []) = [(k, [v])]
| insert (k1v as (k1, v), items as ((k2vs as (k2, vs))::rest)) =
case cmp (k1, k2) of
LESS => (k1, [v]) :: items
| EQUAL => (k2, v::vs) :: rest
| GREATER => k2vs :: insert (k1v, rest)
fun extract (k, vs) = rev vs
in
map extract (List.foldl insert [] (ListPair.zip (ks, vs)))
end
Use a tree for storing pairs:
datatype 'a bintree = Empty | Node of 'a bintree * 'a * 'a bintree
(* post-order tree folding *)
fun fold f e Empty = e
| fold f e0 (Node (left, x, right)) =
let val e1 = fold f e0 right
val e2 = f (x, e1)
val e3 = fold f e2 left
in e3 end
fun group cmp ks vs =
let fun insert ((k, v), Empty) = Node (Empty, (k, [v]), Empty)
| insert (k1v as (k1, v), Node (left, k2vs as (k2, vs), right)) =
case cmp (k1, k2) of
LESS => Node (insert (k1v, left), k2vs, right)
| EQUAL => Node (left, (k2, v::vs), right)
| GREATER => Node (left, k2vs, insert (k1v, right))
fun extract ((k, vs), result) = rev vs :: result
in
fold extract [] (List.foldl insert Empty (ListPair.zip (ks, vs)))
end

OCaml Heap Missing Nodes

I have defined a type heap:
type 'a heap =
| Node of int * int * 'a heap * 'a heap
| Leaf;;
And the following functions:
let rank = function Leaf -> 0 | Node (r,_,_,_) -> r;;
let makeNode x a b =
if rank a>= rank b then Node(rank b+1,x,a,b)
else Node (rank a+1,x,a,b);;
let rec meld = function
|h,Leaf | Leaf,h -> h
| (Node(f,x,a1,b1)as h1),(Node(g,y,a2,b2)as h2) -> if x >= y then makeNode x a1 (meld (b1, h2))
else makeNode y a2 (meld (h1, b2));;
let insert h x = meld ((Node(1,x,Leaf,Leaf)), h);;
However, when I insert a second node into the heap, the root disappears. How can I fix this:
let makeheap x = Node(1,x,Leaf,Leaf);;
let myheap = makeheap 5;;
insert myheap 7;;
insert myheap 8;;
insert myheap 3;;
results in the following output:
val myheap : 'a heap = Node(1,5,Leaf,Leaf)
'a heap = Node(1,7,Leaf,Node(1,5,Leaf,Leaf))
'a heap = Node (1,8,Leaf,Node(1,5,Leaf,Leaf))
'a heap = Node(1,5,Leaf,Node(1,3,Leaf,Leaf))
You're calling insert as if it's an imperative function. I.e., as if it's going to change some state. But your data structure is immutable. You have to think of insert as returning the new state.
You should read up on pure functional programming before going too much farther, I suspect.
The first few chapters of Okasaki's Purely Functional Data Structures explain things very well.
The answer to your immediate question is something like this:
# insert (insert myheap 7) 8;;
- : 'a heap = Node (1, 8, Leaf, Node (1, 7, Leaf, Node (1, 5, Leaf, Leaf)))

Check if a matrix contains a number

I want to check if a matrix of type [[a,b,c][d,e,f]] contains a specific number.
I'm having trouble accessing the list inside the list.
let matrix = [[1;2;3]; [4;5;6]];;
let rec contains mat x = match mat with
| [] -> false
| h::t -> if (h=x) then true else contains t x;;
This work on a one-dimensional list, but I'm just too much of a newbie to get it to work on a two-dimensional.
First off, your function contains is List.mem in the standard library (not that there is anything wrong with reimplementing it to learn OCaml).
Also, if (h=x) then true else contains t x is usually written (h=x) || contains t x.
As for your problem, you need to iterate over each sublist of the matrix (presumably representing a row), and for each row check if it contains the number you're looking for :
# let rec mat_contains mat x = match mat with
| [] -> false
| row::tl -> contains row x || mat_contains tl x;;
val mat_contains : 'a list list -> 'a -> bool = <fun>
# mat_contains matrix 4;;
- : bool = true
As an aside, here it is written using functions in the standard library :
# let mat_contains2 mat x = List.exists (List.mem x) mat;;
val mat_contains2 : 'a list list -> 'a -> bool = <fun>
# mat_contains2 matrix 4;;
- : bool = true