views:

314

answers:

3

Assuming l is a List and elem is an element, how can I return the last occurence of the element elem in the list l? Also return -1 if the element does not exisit in l. I dont quite understand how to use recursion for iterating through the list...

let rec getLastOccurence l elem =

;;

A: 

This is a tail recursive algorithm for finding an integer in a list:

let find_index elt lst =
  (* Wrap inner function that accepts an accumulator to keep the interface clean *)
  let rec find_it elt acc = function
    | hd :: tl when elt = hd -> acc (* match *)
    | hd :: tl -> find_it elt (acc + 1) tl (* non-match *)
    | _ -> raise Not_found (* end of list *)
  in find_it elt 0 lst (* call inner function with accumulator starting at 0 *)
;;
Jeff Ober
I dont understand the line | _ -> raise Not_found
Polly Hollanger
The first two match options catch the case when there is a head and tail element, using the cons operator (::). The _ symbol is a convention saying, "Ignore this match." The pattern matches anything, but since the first two catch everything from a :: b to a :: nothing, the last one is used to catch the situation where we have iterated through the entire list and not found a match. Re-reading your question, you want to change "raise Not_found" to -1.
Jeff Ober
Note that you could also use "| [] -> raise Not_found" for the final pattern. Neither would bind to a variable. They are effectively equivalent.
Jeff Ober
This will find the first index. Polly appears to be looking for the last index. Though you could just do this on `(List.rev lst)` to get the offset from the end of the list.
Chuck
This is wrong. "find_index 1 [1;2;3;1;2]" returns 0.
ygrek
That's not wrong. The first index of 1 in [1;2;3;1;2] is 0.
Jeff Ober
Ah, she wanted the *last* occurrence. Self-downmod for not reading the assignment carefully :)
Jeff Ober
+2  A: 
let findi x l = 
  let rec loop i n l = 
    match l with 
    | y::tl -> loop (i+1) (if y = x then i else n) tl 
    | [] -> n 
  in 
  loop 0 (-1) l;;
ygrek
+1  A: 

Basically, you need two accumulators to keep track of the current index and the maximum index found for the element. Then you just recurse to the end of the list and return the "maximum index" value.

let rindex elem = 
  let rec find_index i max_found = function
    | (x::xs) when x = elem -> find_index (i+1) i xs
    | (_::xs) -> find_index (i+1) max_found xs
    | [] -> max_found
  in find_index 0 (-1);;

This can also be expressed pretty simply as a fold:

let rindex elem ls = 
  let find_index (i, max) elem' = (i+1, if elem' = elem then i else max)
  in snd (fold_left find_index (0, -1) ls);;
Chuck