I have two lists -- one is a grid list of tuples and the other one is a list of coordinates -- to be compared, such that the list of coordinates is always a sublist of the grid list. Now I want to check each tuple in the grid list whether it's in the coordinates list or not. If there exists one, substitute the tuple in the grid list with a "#" and if not, substitute with a "_".
Below is my best attempt and it never works.
getHash :: [(Int,Int)] -> [(Int,Int)] -> [String]
getHash [(x1,y1)] [(x2,y2)] | (x1,y1) `elem` [(x2,y2)] : (x1,y1) = "#"
| otherwise (x1,y1) = "_"
where (x1,y1) <- [(x1,y1)]
You want to replace each element in a list with "#" or "_" depending on whether that element is an element of a second list. We can split that into two parts. The first part, "Replace each element in a list with the result of calling a function with that element as its argument" is map. The second, doing something based on whether an item is an element of a list, does indeed use elem. So we will
map over a list and
call elem on each element,
comparing it with the list of known coordinates, and
decide which string to replace the element of the list with based on the result of the call to elem.
getHash known xs = map (\x -> if x `elem` known then "#" else "_") xs
Now, why did I give the known list first? It's mostly personal preference, but I think it works a bit better with partial application. getHash [(1,2)] is a function that compares a list given as an argument with a static 'known' list. And since xs is the right position for it, we can also use eta reduction in the definition:
getHash known = map (\x -> if x `elem` known then "#" else "_")
Related
Running insert ls n should return a list of piles from taking ls and inserting n so that either n has been added to the head of the first pile in ls whose previous head is greater than or equal to n, or if it doesn't exist, a new pile containing just n is added to the end of ls.
For example,
insert [[4]; [5]] 3 = [[3;4]; [5]]
insert [[2]; [6]] 4 = [[2]; [4;6]]
insert [[3]] 4 = [[3]; [4]]
Basically, I'm trying to use the sort helper function that appends to the list if the element is less than the first in the list, and then in that case to just return the rest of the list.
let rec insert ls n =
match n with
| [] -> [x]
| y::ys -> if x < y then x::y::ys else y::insert x ys;;
let rec sort n =
match n with
| [] -> []
| x::xs -> insert x (sort xs);;
You keep confusing the order and type of arguments in your insert function. In your text description and following from the examples section, insert has type 'a list list -> 'a -> 'a list list, but when you try to write your insert function, you match the element n with a list. In the same manner, when you call insert from sort you pass the element as the first argument.
Next, your insert function shall return a list of lists, but in the first branch of your match, [] -> [x], you return just a list. In addition, there is no x variable bound in this match or anywhere else, probably you meant n?
Finally, when you compare the first element of the input list with the element n you compare the whole pile, instead of the head of the pile.
So let's try to rectify these problems, first of all, we have to match on ls instead of n,
let rec insert ls n =
match ls with
(* ^^
ls not n! *)
Next, if we have an empty input, then we need to return a list containing a single pile, where a pile is a list itself,
| [] -> [[n]] (* a list containing a list with a single element `n` *)
Finally, when we match on the head of the input list, we have to keep in mind that the head is the list itself, i.e., a pile, so we need to unpack it as well,
| (x::xs)::ys ->
(* ^^^^^^^
here x is the head of the pile, and x::xs is the whole pile *)
and pack it back,
if n < x then (n::x::xs)::ys else (x::xs)::insert ys n
(* ^^^^^^^^^^ ^^^^^^^
extended pile intact pile *)
The next step would be to make the match complete, i.e., to think what to do when the pile is empty itself (could it be?) and what to do when x is equal to n.
Good morning,
I have a problem with coding using ocaml so I had to code a function that take on input list then add to this list an element.
But using this does'nt affect the list1 so how can I do this ?
Thank you.
let rec append list1 element list2 = match list2 with
[]-> list1
| e::l -> if ( element = e ) then e :: list1
else (append list1 element l)
;;
List are immutable in OCaml, you can't change this. You can write a function append that takes a list and returns a new list that appends an element to it.
For example, here is the prepend function that takes a list and an element and returns a new list with the given element prepended to the passed list,
let prepend xs x = x :: xs
The append function is a little bit trickier, since lists in OCaml are singly-linked, so it is easy to prepend but hard to append. To implement the append function you need an intermediate list, let's call it acc for accumulator. You then go through each element of the input list and add it to the accumulator. Since you're prepending, then once the input list is over your accumulator will have all the elements of the input list by in the reversed order, i.e., the first element (aka the head) of the acc list will be the last element of the input list. Now you what is left is to prepend the element that we want to append to the reversed acc list and reverse act. Here is the skeleton code for you
let append xs x =
let rec loop xs acc = match xs with
| ... -> ... in
loop xs []
The Problem Statement: Write a function pair that takes two lists of integers and generates a list of pairs, where each pair is a combination of each element from each list.
For example, pair ([1,2], [3,4,5]) should return
[(1,3), (1,4), (1,5), (2,3), (2,4), (2,5)].
My work so far:
-fun pair(a:int list, b:int list) = if null a then nil else if null b then nil else (hd a, hd b)::pair(a, tl b)#pair(tl a, b);
val pair = fn : int list * int list -> (int * int) list
-pair([1,2],[3,4,5]);
val it = [(1,3),(1,4),(1,5),(2,5),(2,4),(2,5),(2,3),(2,4),(2,5)]
I've tried to trace the function to find out why the (2,5), (2,4), (2,5) are showing up but I'm not seeing it clearly still.
It seems straightforward enough but I can't seem to get the last bits ironed out. Some assistance pinpointing why those elements are being added in the middle would be of help.
Thanks.
Peter
The main problem is that you're recursing over both lists.
If you look at your example,
pair ([1,2], [3,4,5]) -> [(1,3), (1,4), (1,5), (2,3), (2,4), (2,5)]
you will see that it has two sublists,
[(1,3), (1,4), (1,5)]
[(2,3), (2,4), (2,5)]
where the first consists of pairs formed from the first element of [1,2] and every element of [3,4,5], and the second is the second element of [1,2] also paired with every element of [3,4,5].
Note that each sublist contains all of [3,4,5] but only one element of [1,2] - the first is the same as pair ([1], [3,4,5]) and the second is pair ([2], [3,4,5]) - so you should only need to recurse over the first list.
You can create such a list like this:
If any input list is empty, the result is empty.
Otherwise:
Take the first element of a and pair it with every element of b in a list (hint: think about map.)
Recursively make pairs from the tail of a and all of b.
Combine the results of 1 and 2.
With pattern matching:
fun pair ([], _) = []
| pair (_, []) = []
| pair (x::xs, ys) = <something involving x and ys, suitably combined with 'pairs (xs, ys)'>
It might help if you write step 1 as a separate function.
Since this is an exercise, I'm not going to show you the answer to the problem statement.
What you're trying to generate is called the cartesian product of the two lists.
Your current approach (formatted a bit nicer),
fun pair (a, b) =
if null a then nil else
if null b then nil else
(hd a, hd b) :: pair (a, tl b) # pair (tl a, b);
produces duplicate results down the line because you leave out hd b in pair (a, tl b) and you leave out hd a in pair (b, tl a), but on the second iteration of e.g. pair (a, tl b), the first element of a is processed once again for each remaining element of tl b.
You can avoid this duplication of work by addressing each element once. I would recommend that you look at the functions map and concat. The general approach is this: For every element x of a, generate (x,y) for every element y of b. "For every element" is map. And
map (fn x => ...something with (x,y)...) a
produces a list of results, just like you want. But if you repeat the same approach of map (fn y => ...) b as the ...something with (x,y)... part, you'll run into an inconvenient surprise that concat can help you with.
You can solve this exercise without using map and concat and instead using manual recursion, but you might have to split the work into two functions, since you'll want one function that folds over the x of a and, for each x, fold once over b. The function map takes the recursion part that both of these functions would have in common and lets you only write the things they don't have in common.
I have two strings
a :: [String]
a = ["A1","A2","B3","C3"]
and
b :: [String]
b = ["A1","B2","B3","D5"]
And I want to calculate the difference between two strings based on the first character and second character and combination of two characters.
If the combination of two elements are the same, it would be calculate as 1
The function I declared is
calcP :: [String] -> [String] -> (Int,[String])
calcP (x:xs) (y:ys) = (a,b)
where
a = 0 in
???
b = ????
I know that I should have a increment variable to count the correct element, and where I should put it in? For now I totally have no idea about how to do that, can anyone give me some hint??
The desired result would be
(2,["B2","D5"])
How should I do that?
I assume that the lists have the same size.
The differences between the two lists
Let's focus on the main part of the problem:
Prelude> a=["A1","A2","B3","C3"]
Prelude> b=["A1","B2","B3","D5"]
First, notice that the zip method zips two lists. If you use it on a and b, you get:
Prelude> zip a b
[("A1","A1"),("A2","B2"),("B3","B3"),("C3","D5")]
Ok. It's now time to compare the terms one to one. There are many ways to do it.
Filter
Prelude> filter(\(x,y)->x/=y)(zip a b)
[("A2","B2"),("C3","D5")]
The lambda function returns True if the elements of the pair are different (/= operator). Thus, the filter keeps only the pairs that don't match.
It's ok, but you have to do a little more job to keep only the second element of each pair.
Prelude> map(snd)(filter(\(x,y)->x/=y)(zip a b))
["B2","D5"]
map(snd) applies snd, which keeps only the second element of a pair, to every discordant pair.
Fold
A fold is more generic, and may be used to implement a filter. Let's see how:
Prelude> foldl(\l(x,y)->if x==y then l else l++[y])[](zip a b)
["B2","D5"]
The lambda function takes every pair (x,y) and compares the two elements. If they have the same value, the accumulator list remains the identical, but if the values are different, the accumulator list is augmented by the second element.
List comprehension
This is more compact, and should seem obvious to every Python programmer:
Prelude> [y|(x,y)<-zip a b, x/=y] -- in Python [y for (x,y) in zip(a,b) if x!= y]
["B2","D5"]
The number of elements
You want a pair with the number of elements and the elements themselves.
Fold
With a fold, it's easy but cumbersome: you will use a slightly more complicated accumulator, that stores simultaneously the differences (l) and the number of those differences (n).
Prelude> foldl(\(n,l)(x,y)->if x==y then (n,l) else (n+1,l++[y]))(0,[])$zip a b
(2,["B2","D5"])
Lambda
But you can use the fact that your output is redundant: you want a list preceeded by the length of that list. Why not apply a lambda that does the job?
Prelude> (\x->(length x,x))[1,2,3]
(3,[1,2,3])
With a list comprehension, it gives:
Prelude> (\x->(length x,x))[y|(x,y)<-zip a b, x/=y]
(2,["B2","D5"])
Bind operator
Finally, and for the fun, you don't need to build the lambda this way. You could do:
Prelude> ((,)=<<length)[y|(x,y)<-zip a b,x/=y]
(2,["B2","D5"])
What happens here? (,) is a operator that makes a pair from two elements:
Prelude> (,) 1 2
(1,2)
and ((,)=<<length) : 1. takes a list (technically a Foldable) and passes it to the length function; 2. the list and the length are then passed by =<< (the "bind" operator) to the (,) operator, hence the expected result.
Partial conclusion
"There is more than than one way to do it" (but it's not Perl!)
Haskell offers a lot of builtins functions and operators to handle this kind of basic manipulation.
What about doing it recursively? If two elements are the same, the first element of the resulting tuple is incremented; otherwise, the second element of the resulting tuple is appended by the mismatched element:
calcP :: [String] -> [String] -> (Int,[String])
calcP (x:xs) (y:ys)
| x == y = increment (calcP xs ys)
| otherwise = append y (calcP xs ys)
where
increment (count, results) = (count + 1, results)
append y (count, results) = (count, y:results)
calcP [] x = (0, x)
calcP x [] = (0, [])
a = ["A1","A2","B3","C3"]
b = ["A1","B2","B3","D5"]
main = print $ calcP a b
The printed result is (2,["B2","D5"])
Note, that
calcP [] x = (0, x)
calcP x [] = (0, [])
are needed to provide exhaustiveness for the pattern matching. In other words, you need to provide the case when one of the passed elements is an empty list. This also provides the following logic:
If the first list is greater than the second one on n elements, these n last elements are ignored.
If the second list is greater than the first one on n elements, these n last elements are appended to the second element of the resulting tuple.
I'd like to propose a very different method than the other folks: namely, compute a "summary statistic" for each pairing of elements between the two lists, and then combine the summaries into your desired result.
First some imports.
import Data.Monoid
import Data.Foldable
For us, the summary statistic is how many matches there are, together with the list of mismatches from the second argument:
type Statistic = (Sum Int, [String])
I've used Sum Int instead of Int to specify how statistics should be combined. (Other options here include Product Int, which would multiply together the values instead of adding them.) We can compute the summary of a single pairing quite simply:
summary :: String -> String -> Statistic
summary a b | a == b = (1, [ ])
| otherwise = (0, [b])
Combining the summaries for all the elements is just a fold:
calcP :: [String] -> [String] -> Statistic
calcP as bs = fold (zipWith summary as bs)
In ghci:
> calcP ["A1", "A2", "B3", "C3"] ["A1", "B2", "B3", "D5"]
(Sum {getSum = 2},["B2","D5"])
This general pattern (of processing elements one at a time into a Monoidal type) is frequently useful, and spotting where it's applicable can greatly simplify your code.
I'm tasked with creating a list of m word portmanteaus with n letter overlap from a given list of words.
For example, a 2 word 2 letter overlap portmanteau would be: "collegenetics" made from "college" and "genetics". A 3 word 2 letter overlap could be "firegaluminum" made of "fire", "regal" and "aluminum".
I have written a function singleport with this syntax:
let singleport word1 word2 n =
match suffix word1 n = prefix word2 n with
| false -> "No Port"
| true -> word1 ^ (prefixless word2 n)
which identifies whether or not two words could be portmanteaus. However, I'm struggling to identify a way to run this recursively in order to compare two elements of a list, all while constructing a new list that records all the possible portmantaus.
I figured List.fold_left could be used because of the use of the accumulator, but I don't know how to implement it and I would greatly appreciate any advice. Thank you very much!
One of the approaches to attack this task is to split it into small understandable subtasks, and then try to merge them. This is the deductive approach.
Deductively
Applying the deductive method to your task, we can split it in the following way:
create a list of consecutive pairs
map the list for portmanteaus
join the result
To create a list of pairs, you need to write the following function:
(** [pair_list xs] given the list [xs], produces a list of consecutive pairs.
Fails with an invalid argument, if the list has odd length. *)
val pair_list : 'a list -> ('a * 'a) list
With such a function, you can use map to transform each pair to a list of portmanteau, mapping a pair to an empty list, if it is impossible. E.g., given this function:
val portmanteau : (string * string) -> string list
And now we can join everything with List.concat:
let portmanteau_of_list xs =
List.map portmanteau (pair_list xs) |> List.concat
Inductively
Another approach is to move from the opposite direction, i.e., not from top to down, but from the bottom. So inductive reasoning about this task would be the following:
portmanteaus of an empty list is an empty list,
portmanteaus of the list of one element is an error
portmanteaus of a list that is greater than two when the first two elements don't form a portmanteau is the portmanteaus of the rest elements of the list
portmanteaus of a list greater than two when the first two elements form a portmanteau is the portmanteaus of these two elements plus portmanteaus of the rest elements of the list.
The same in OCaml (untested):
let rec portmanteau_of_list = function
| [] -> []
| [_] -> failwith "odd list"
| x :: y :: xs -> match portmanteau x y with
| None -> portmanteau_of_list xs
| Some p -> p :: portmanteau_of_list xs