If I have a list [1;2;3;4;5;6] and I want to return a list of the odd indices [2;4;6], could I do this with List.map and some function? I'm having difficulty figuring this out.
What List.map does is return a function (call it f say) of each of the elements of the list. For each element x of the input list, it returns f x in the resulting list. Hence, the returned list is always the same length as the one it is passed.
Since you want a shorter list, you can't use List.map.
As #UnholySheep says, you could use List.filteri. It's specifically intended for returning only some of the elements of the list based on their position in the list.
In OCaml, suppose I have a string list as follows:
let ls : string list = ["A"; "A"; "B"; "B"; "A"; "Y"; "Y"; "Y"] ;;
I'm having trouble writing a function that calculates how many times an element occurs consecutively and also pairs up that element with its frequency. For instance, given the above list as input, the function should return [("A", 2); ("B", 2), ("A", 1), ("Y", 3)].
I've tried looking for some hints elsewhere but almost all other similar operations are done using int lists, where it is easy to simply add numbers up. But here, we cannot add strings.
My intuition was to use something like fold_left in some similar fashion as below:
let lis : int list = [1;2;3;4;5]
let count (lis : int list) = List.fold_left (fun x y -> x + y) (0) (lis)
which is essentially summing all the elements cumulatively from left to right. But, in my case, I don't want to cumulatively sum all the elements, I just need to count how many times an element occurs consecutively. Some advice would be appreciated!
This is obviously a homework assignment, so I will just give a couple of hints.
When you get your code working, it won't be adding strings (or any other type) together. It will be adding ints together. So you might want to look back at those examples on the net again :-)
You can definitely use fold_left to get an answer. First, note that the resultl is a list of pairs. The first element of each pair can be any type, depending on the type of the original list. The second element in each pair is an int. So you have a basic type that you're working with: ('a * int) list.
Imagine that you have a way to "increment" such a list:
let increment (list: ('a * int) list) value =
(* This is one way to think of your problem *)
This function looks for the pair in the list whose first element is equal to value. If it finds it, it returns a new list where the associated int is one larger than before. If it doesn't find it, it returns a new list with an extra element (value, 1).
This is the basic operation you want to fold over your list, rather than the + operation of your example code.
I'm writing OCaml code that reads in a list and removes any char 'i's that appear at the beginning of the list. For instance, the list removeI['i';'i';'a';'c';'i'] should return -: int * char list = ['a';'c';'i'], because there are 2 'i's at the beginning of the list. I believe I know how to implement this properly; however, I want to return a tuple that includes the number of removed 'i's as well as the new list with the 'i's removed. I know that may sound confusing, but an example would be removeI['i';'i';'a';'c';'i'] -: int * char list = (2,['a';'c';'i']) There are 2 'i's removed and the new list with the removed 'i's.
So far, I have the following function:
let rec removeI list = match list with
| [] -> []
| x::[] -> x::[]
| x::y::t1 -> if x='i' then removeI (y::t1)
else list;;
This returns the list with the first 'i's removed, but I keep getting errors when I try to include the number of removed 'i's as part of a tuple. Could anyone push me in the right direction? Thanks!
Your recursive call will return the same type as the function overall. So if you change the function to reuturn (count, list), then the recursive call will return that also.
Generally you want to gather up the returned values and calculate a new value from them.
Right now you have just this:
removeI (y :: t1)
But you need something more like this:
let (count, list) = removeI (y :: t1) in
(* Newly calculated count and list *)
Note that your base cases also have to return a count and a list.
As a side comment, I don't actually understand your second base case. You don't want to remove an 'i' if it's the only thing in the list? That doesn't seem particularly consistent.
I am trying to write a function to delete a list from another list.
''a list -> ''a list -> ''a list
Here's what I have so far:
fun delete _ [] = [] |
delete (h1::t1) (h2::t2) =
if h1=h2
then t2
else h2::delete (h1::t1) t2;
I am using MoscowML and it gives me a Warning: pattern matching is not exhaustive error.
A test of the above function:
- delete [4,5] [1,2,3,4,5,6,7,8];
> val it = [1,2,3,5,6,7,8] : int list
The desired output is:
> val it = [1,2,3,6,7,8] : int list
There are two issues here:
1- Why is the interpreter raising the Warning: pattern matching is not exhaustive error
2- What can be done to make the code working.
Concerning the first point, the reason for the warning is because that you are not checking every possibility that may occur. The function delete as it currently stands checks only for two possibilities:
-1 The second list being the empty list (covered by the pattern: _ [] = )
-2 Both lists not being empty (covered by the second pattern: (h1::t1) (h2::t2) =)
However, there is a third possibility, namely the first list being the empty list. Therefore, the following input would result in an error: delete [] [1,2,3,4,5,6]
Concerning the second point, if the exact requirement is to delete from the second list the elements of the first list in succession and only once, then your solution is very close. The else branch is fine, only the then branch needs more attention.
By correcting the then branch I get following results:
delete [4,5] [1,2,3,4,5,6,7,8] = [1,2,3,6,7,8];
delete [5,4] [1,2,3,4,5,6,7,8] = [1,2,3,4,6,7,8];
delete [4,4,5] [1,2,3,4,5,6,7,8] = [1,2,3,5,6,7,8];
delete [4,5,6] [1,2,3,4,5,6,7,8] = [1,2,3,7,8];
delete [4,6,5] [1,2,3,4,5,6,7,8] = [1,2,3,5,7,8];
delete [4,6,5] [1,2,3,4,6,7,8,5] = [1,2,3,7,8];
If however you want to delete all the elements of the first list occurring in the second list regardless of their order, then you will need to rethink your approach.
for instance, if you want the following result:
delete [4,6,5] [1,2,3,4,4,5,5,5,4,4,6,6,5,5,6,6,6,6,6,7,8,5] = [1,2,3,7,8];
then you need to do it in two steps:
First write a function del that given one element will delete all its occurrences in a list: fun del e l = ...
The implementation thereof is practically identical to the one you provided for delete, except you will need to change the then branch slightly.
After you have del, now you can implement the function delete that given a list, it will delete all the occurrences of that list in the second list. Here you will use the previously defined function del.
In F# at some point I have many lists (the actual number of them differs for input data) and I want to make an aggregation over all those lists (let say addition for simplification). So what I want to achieve is the same what List.map2 or List.map3 does but for bigger number of lists.
How can I approach it? I was wondering if this is possible to do with List.scan?
You can use List.reduce and do something like this:
> let lists = [[1;2;3]; [1;2;3]; [1;2;3]]
val lists : int list list = (...)
> lists |> List.reduce (List.map2 (+));;
val it : int list = [3; 6; 9]
What does this do?
List.reduce takes a list of values (here the value is int list) and it aggregates them into a single value using a function that says how to merge two values. So in this case, we need to give it a function int list -> int list -> int list and it will call it on the first and the second list, then on the result and the third list (and so on).
The argument List.map2 (+) is a function of the right type - it takes two lists and performs pairwise sum of the two lists. This is really just a shortcut for writing something like:
lists |> List.reduce (fun list1 list2 ->
List.map2 (fun a b -> a + b) list1 list2)