I would like to create a function that turns this list into a new list of lists splitting this one each time it says "gap"
["dash", "dot", "dot", "gap", "dash", "dash", "dash", "gap", "dash", "dash", "dot", "gap"]
would become
[["dash", "dot", "dot"], ["dash", "dash", "dash"], ["dash", "dash", "dot"]]
any idea appreciated as lets say i have spent a lot of time on this with no luck...
format :: [String] -> [[String]]
format []
= []
format (x:xs)
| x == "gap" = []
| otherwise = x : (format xs)
main :: IO()
main =
putStrLn ( show ( format ["dash", "dot", "dot", "gap", "dash", "dash", "dash", "gap", "dash", "dash", "dot", "gap"] ) )
This is what I've been working around but I'm getting caught up with type errors and even if I get them sorted I reckon it will only run until the first "gap"...
span function does the job.
format :: [String] -> [[String]]
format ("gap":ws) = format ws
format [] = []
format ws = let (w1, w2) = span (/= "gap") ws
in w1:format w2
You may also use foldr for this job
let fun = foldr (\l a -> case l of
"gap" -> [] : a
_ -> (l : (head a)) : (tail a)) []
Prelude> fun ["dash", "dot", "dot", "gap", "dash", "dash", "dash", "gap", "dash", "dash", "dot", "gap"]
[["dash","dot","dot"],["dash","dash","dash"],["dash","dash","dot"]]
If the current element l is a "gap" then lets insert a new empty list [] to the head of our accumulating list a or else lets take the head of our accumulating list a, insert the current element l to the head of our list and insert it to the tail of our accumulating list a.
The above method might introduce some blank sublists if there are consequtive "gap"s. So if that is a possibility then another approach could be.
let ff = filter (not . elem "gap") . groupBy (\x y -> x /= "gap" && y /= "gap")
Prelude> ff ["dash", "dot", "dot", "gap", "gap", "dash", "dash", "dash", "gap", "dash", "dash", "dot", "gap"]
[["dash","dot","dot"],["dash","dash","dash"],["dash","dash","dot"]]
Related
Write a function that combines the two lists provided. Items in the output list are to alternate. You must not use library functions (e.g. "length", "reverse", "append") of complexity greater than O(1).
My code:
let rec zip(aList, bList) list =
let rec first(aLst, bLst) list =
if(aLst = [] && bLst = []) then []
else if(aLst = []) then second(aLst,bLst)
else aLst.hd :: second(aLst.tl, bLst)
let rec second(aLst, bLst) list =
if(aLst = [] && bLst = []) then []
else if(bLst = []) then first(aLst,bLst)
else bLst.hd :: first(aLst, bLst.tl);;
zip([1;2;3;4;5], [-6]);;
zip([1;2;3;4;5],[]);;
zip([-6],[1;2;3;4;5]);;
The problem:
let rec second(aLst, bLst) list =
Error: Syntax error
I'm also afraid of rec - is it gonna work properly?
A common recursive pattern for alternation is to swap the arguments in recursive calls, eg.
let rec zip a b =
match a with
| [] -> b
| x :: a' -> x :: zip b a' (* swap arguments *)
zip [-6;-5;-4] [1;2;3];;
(* - : int list = [-6; 1; -5; 2; -4; 3] *)
The syntax for a nested let is
let v = expr0 in expr
You forgot both the in and the final expr.
let rec zip(aList, bList) list =
let rec first(aLst, bLst) list =
if(aLst = [] && bLst = []) then []
else if(aLst = []) then second(aLst,bLst)
else aLst.hd :: second(aLst.tl, bLst)
in
let rec second(aLst, bLst) list =
if(aLst = [] && bLst = []) then []
else if(bLst = []) then first(aLst,bLst)
else bLst.hd :: first(aLst, bLst.tl)
in
first (aLst, bLst)
;;
Next problem is that first and second are mutually recursive. This requires the use of and:
let rec zip(aList, bList) list =
let rec first(aLst, bLst) list =
if(aLst = [] && bLst = []) then []
else if(aLst = []) then second(aLst,bLst)
else aLst.hd :: second(aLst.tl, bLst)
and second(aLst, bLst) list =
if(aLst = [] && bLst = []) then []
else if(bLst = []) then first(aLst,bLst)
else bLst.hd :: first(aLst, bLst.tl)
in
first (aLst, bLst)
;;
Next what is up with (aLst, bLst) list? What is the "list" supposed to be there? Remove those across the board.
And last ocaml lists are not objects. Ocaml has objects but methods are called with #. Neither are lists records that have labels hd and tl. So aLst.hd makes no sense. You have to use List.hd aLst instead. Even better would be pattern matching but you don't seem to have learned about that yet.
Put it all together and you get:
let rec zip(aList, bList) =
let rec first(aLst, bLst) =
if(aLst = [] && bLst = []) then []
else if(aLst = []) then second(aLst,bLst)
else List.hd aLst :: second(List.tl aLst, bLst)
and second(aLst, bLst) =
if(aLst = [] && bLst = []) then []
else if(bLst = []) then first(aLst,bLst)
else List.hd bLst :: first(aLst, List.tl bLst)
in
first (aList, bList)
;;
# zip([1;3;5], [2;4;6]);;
- : int list = [1; 2; 3; 4; 5; 6]
I have a source list that looks like:
let source = ["A", "B", "%", "C", "Y", "%"]
I want to go through each element and each time I hit the token "%", every element of the preceding list should go into a sub list. The result should look like this.
let result = [["A", "B"], ["C", "Y"]]
I think I have to use the fold function of list, but my result type is string list instead of string list list
let folder (acc, current) item =
match item with
| "" -> (current # acc, [])
| _ -> (acc, current # [item])
let result = source
|> List.fold folder ([], [])
|> fun (a,_) -> a
Any ideas?
You were very close, but I think one issue was your source list was actually a list with one big tuple in it. You have to separate list items with ;. Comma , is used to separate items in a tuple.
let source = ["A"; "B"; "%"; "C"; "Y"; "%"]
Then with some minor changes to your folder function:
let folder (acc, current) item =
match item with
| "%" -> (acc # [current], [])
| _ -> (acc, current # [item])
You now get the result you want:
let result =
source
|> List.fold folder ([], [])
|> fst
> val result : string list list = [["A"; "B"]; ["C"; "Y"]]
This is not as generic but you can take advantage of string operations to do this more succinctly.
(String.concat "" source).Split([|'%'|], StringSplitOptions.RemoveEmptyEntries)
|> List.ofArray
|> List.map List.ofSeq
Assumes Taylor's fix to source to make it a proper list.
Im trying to write a function that does the following, takes in :
[ #"t" ,#"h" ,#"e" ,#" " ,#"c" ,#"a" ,#"t" ]
The following is the output:
( [#"t" ,#"h" ,#"e" ] , [#" " ,#"c" ,#"a" ,#"t" ] )
so far I have..
fun isLetter c = #"a" <= c andalso c <= #"z";
//(this works fine and is used within the main function wordPop)
fun wordPop [] = ([],[])
| wordPop (hd::tl) = if not (isLetter hd)
then ([], hd::tl)
else (* ...not too sure... (1) *)
I know that I have to do something that looks like this at (1)
let (wordPop tl) in (x,y) end;
and somehow add hd to x. But not 100% sure how to do this.
Sounds like homework, so here is a hint:
In the non-basis case (hd::tl), if isLetter hd is false then you are ready to directly return something (no need for a recursive function call). Think carefully about what you want to return if the input looks like just explode(" cat") (i.e. [#" ", "c", "a", "t"] -- note the space).
As far as the other case (isLetter hd evaluating to true) goes, suppose you are processing the characters in "he cat". Then hd = #"h" and tl = [#"e", #" ", "c", "a", "t"].
If in this context you execute
let val (x,y) = wordPop tl
then x = [#"e"] and y = [#" ", "c", "a", "t"].
Given such x and y -- where do you want to place hd = #"h" before returning?
The final solution I got:
fun isLetter c = #"a" <= c andalso c <= #"z";
fun wordPop [] = ([],[]) |
wordPop (hd::tl) = if(not (isLetter hd))
then ([],(hd::tl))
else let val (x,y) = wordPop tl in (hd::x,y) end;
I want to write a function that takes as argument a list of tuples like this:
remove' [ ("a", True), ("b", False), ("c", False), ("d", True) ]
I would like to return a list of tuples that have False as their second value, so I'd like my function to return
[ ("b", False), ("c", False) ]
Here's what I have so far but it won't load in GHCi. can anyone help me out? Thanks
remove' :: [(a,b)] -> [(a,b)]
remove' [(a,b)] = [ c | c <- [(a,b)], c `notElem` True ]
Since you want to match the second element of the tuples, you need to pick the second element from the tuple and compare it with False like this
remove' :: [(a, Bool)] -> [(a, Bool)]
remove' xs = [c | c <- xs, snd c == False]
The snd function will get second element from each of the tuples and compare them with False. Only if they match, they will be gathered in the resulting list.
Since the second elements are booleans, you can make use of the not function like this
[c | c <- xs, (not . snd) c]
We can express the same wihtout the dot notation like this
[c | c <- xs, not(snd(c))]
Note: In your program, you have
remove' [(a,b)] = ...
it means that, it will be executed only when remove is called with a list of tuples of size 1. You can check that like this
remove' :: [(a, Bool)] -> [(a, Bool)]
remove' [(a, b)] = [(a, b)]
remove' [ ("a", True), ("b", False), ("c", False), ("d", True) ]
will print
Non-exhaustive patterns in function remove'
It means the patterns you specified in the function definition is not covering all the possible inputs. Since we need process a list of tuples of any length, we accept it in xs and use it in the List Comprehension.
I'm surprised no one has yet said
remove' = filter (not . snd)
You just need filter and select second item in lambda:
filter (\x -> (snd x) == False) [("a", False), ("b", True)]
Response:
[("a",False)]
I have two lists :
let a = ["a";"b"];
let b = ["c";"d"];
I want an output list c such as :
c = ["a";"c";"a";"d";"b";"c";"b";"d"];
How to do it in ocaml as lists are immutable? I am new to it.
You would return a new list. If you really are interested in the cartesian product of the lists, then this should be enough:
let cartesian l l' =
List.concat (List.map (fun e -> List.map (fun e' -> (e,e')) l') l)
# cartesian ["a";"b"] ["c";"d"];;
- : (string * string) list = [("a", "c"); ("a", "d"); ("b", "c"); ("b", "d")]
If you need that strange flat structure instead, you can use an additional list concatenation.
let flat_cartesian l l' =
List.concat (List.concat (
List.map (fun e -> List.map (fun e' -> [e;e']) l') l))
If you do not want to use concatenation, because this is not a tail recursive operation, you can use the following (which should be more efficient):
let product l1 l2 =
List.rev (
List.fold_left
(fun x a ->
List.fold_left
(fun y b ->
b::a::y
)
x
l2
)
[]
l1
)
;;
For the cartesian product, just change
b::a::y
into
(a,b)::y
I would break the problem into two sub problems:
Firstly consider a function appendeach with takes a value and a list and returns the result of adding that value infront of each item in the list
let rec appendeach x lst = match lst with [] -> []
| hd::tl -> x::hd::(appendeach x tl);;
Then consider a function product with takes two lists and calls appendeach for each item in the first list and the whole second list
let rec product lst1 lst2 = match lst1 with [] -> [] |
hd::tl -> (appendeach hd lst2)#(product tl lst2);;
Here's an implementation for any number of lists, based on Python's itertools.product.
The lists all have to be the same type, because the products we return will themselves be (necessarily homogenous) lists.
let product pools =
let result = ref [[]] in
List.iter (fun pool ->
result := List.concat_map (fun y ->
List.map (fun x ->
List.append x [y]
) !result
) pool
) pools;
!result
product [["a";"b"]; ["1";"2"]; ["$";"%"]];;
- : string list list =
[["a"; "1"; "$"]; ["b"; "1"; "$"]; ["a"; "2"; "$"]; ["b"; "2"; "$"];
["a"; "1"; "%"]; ["b"; "1"; "%"]; ["a"; "2"; "%"]; ["b"; "2"; "%"]]
If you then need a flattened list you can wrap it in List.concat as per the other answers:
List.concat (product [["a";"b"]; ["1";"2"]]);;
- : string list = ["a"; "1"; "b"; "1"; "a"; "2"; "b"; "2"]
A very imperative (java-like or C-like) solution so I'm not sure it will help; in functional languages like OCaml is usually expected recursion rather than loops. But it works:
let cartesianProduct list1 list2 =
let product = ref [] in
for i = 0 to List.length list1 -1 do
for j = 0 to List.length list2 -1 do
product:= !product#[List.nth list1 i]#[List.nth list2 j]
done;
done;
!product;;