I have a function that takes in a list, and if there are 2 identical and successive numbers in the list, and if there is a number, x, elsewhere in the list, that is equivalent, then I want to change x to 0 and return the list.
twoAdjThenThirdZero (x:y:xs) = [if x == y && x `elem` xs then 0 else x | x <- xs]
For some reason, it is omitting the first two elements in the list every time I try to run it.
*Main> twoAdjThenThirdZero [2,3,4,1,2,0,2,3,3]
[4,1,2,0,2,0,0]
Also, the above case is doing the opposite of what I would like. I want to keep the two 3's at the end of the list and make the second element, that 3, to be 0. But it was switched around.
*Main> twoAdjThenThirdZero [2,2,3,1,2,4]
[3,1,0,4]
Does anyone know why this is? Thanks in advance!
Try this:
adjToZero = adjToZero' (allDoubles xs)
adjToZero' ds [] = []
adjToZero' ds [x] = [x]
adjToZero' ds (x:y:xs) = if (x/=y) && (x `elem` ds) then 0:(adjToZero' ds (y:xs))
else x:(adjToZero' ds (y:xs))
allDoubles [] = []
allDoubles (x:y:xs) = if (x==y) then x:(allDoubles xs)
else allDoubles (y:xs)
Example:
> adjToZero [1,2,1,1]
[0,2,1,1]
I see multiple problems here. You start by destructuring the parameter list in the function declaration twoAdjThenThirdZero (x:y:xs). If you want to continue to get x and y for each step, you have to recurse. Instead you switch to using a list comprehension, and a duplicate of x. In the list comprehension you go through xs, which is all elements of the function parameter except the first two (x and y).
If you read the list comprehension out loud I think you can figure it out.
"if x equals y and x is an element of xs then zero else x, for every x in xs". But you want it done for every x in x+y+xs! You are also using the name "x" in two ways, both in your destructuring of the function arguments and as a variable in the list comprehension.
EDIT:
Now I see what you mean. You just have to add that explicit recursion to what you have already.
twoAdjThenThirdZero [] = []
twoAdjThenThirdZero [x] = [x]
twoAdjThenThirdZero (x:y:xs)
| x == y && x `elem` xs = x : y : twoAdjThenThirdZero [if z == x then 0 else z | z <- xs]
| otherwise = x : twoAdjThenThirdZero (y:xs)
I hope that makes sense to you, if it doesn't, I'll try to explain it further!
EDIT:
phynfo has posted a slightly simpler version of what I was writing!
Related
My homework has been driving me up the wall. I am supposed to write a function called myRepl that takes a pair of values and a list and returns a new list such that each occurrence of the first value of the pair in the list is replaced with the second value.
Example:
ghci> myRepl (2,8) [1,2,3,4]
> [1,8,3,4].
So far I have something like this (but its very rough and not working well at all. I need help with the algorithm:
myRep1 (x,y) (z:zs) =
if null zs then []
else (if x == z then y : myRep1 zs
else myRep1 zs )
I don't know how to create a function that takes a pair of values and a list. I'm not sure what the proper syntax is for that, and I'm not sure how to go about the algorithm.
Any help would be appreciated.
How about something like:
repl (x,y) xs = map (\i -> if i==x then y else i) xs
Explanation
map is a function that takes a function, applies it to each value in the list, and combines all the return values of that function into a new list.
The \i -> notation is a shortcut for writing the full function definition:
-- Look at value i - if it's the same as x, replace it with y, else do nothing
replacerFunc x y i = if x == y then y else i
then we can rewrite the repl function:
repl (x, y) xs = map (replacerFunc x y) xs
I'm afraid the map function you just have to know - it is relatively easy to see how it works. See the docs:
http://www.haskell.org/hoogle/?hoogle=map
How to write this without map? Now, a good rule of thumb is to get the base case of the recursion out of the way first:
myRep1 _ [] = ???
Now you need a special case if the list element is the one you want to replace. I would recommend a guard for this, as it reads much better than if:
myRep1 (x,y) (z:zs)
| x == z = ???
| otherwise = ???
As this is home work, I left a few blanks for you to fill in :-)
myRepl :: Eq a => (a, a) -> [a] -> [a]
myRepl _ [] = []
myRepl (v, r) (x : xs) | x == v = r : myRepl (v, r) xs
| otherwise = x : myRepl (v, r) xs
Untupled arguments, pointfree, in terms of map:
replaceOccs :: Eq a => a -> a -> [a] -> [a]
replaceOccs v r = map (\ x -> if x == v then r else x)
Anyone able to offer any advice for a function in SML that will take 2 lists and return the XOR of them, so that if you have the lists [a,b,c,d], [c,d,e,f] the function returns [a,b,e,f] ?
I have tried to do it with 2 functions, but even that does not work properly.
fun del(nil,L2) = nil
|del(x::xs,L2)=
if (List.find (fn y => y = x) L2) <> (SOME x) then
del(xs, L2) # [x]
else
del(xs, L2);
fun xor(L3,L4) =
rev(del(L3,L4)) # rev(del(L4,L3));
Your attempt seems almost correct, except that fn x => x = x does not make sense, since it always returns true. I think you want fn y => y = x instead.
A couple of other remarks:
You can replace your use of List.find with List.filter which is closer to what you want.
Don't do del(xs,L) # [x] for the recursive step. Appending to the end of the list has a cost linear to the length of the first list, so if you do it in every step, your function will have quadratic runtime. Do x :: del(xs,L) instead, which also allows you to drop the list reversals in the end.
What you call "XOR" here is usually called the symmetric difference, at least for set-like structures.
The simplest way would be to filter out duplicates from each list and then concatenate the two resulting lists. Using List.filter you can remove any element that is a member (List.exists) of the other list.
However that is quite inefficient, and the below code is more an example of how not to do it in real life, though it is "functionally" nice to look at :)
fun symDiff a b =
let
fun diff xs ys =
List.filter (fn x => not (List.exists ( fn y => x = y) ys)) xs
val a' = diff a b
val b' = diff b a
in
a' # b'
end
This should be a better solution, that is still kept simple. It uses the SML/NJ specific ListMergeSort module for sorting the combined list a # b.
fun symDiff1 a b =
let
val ab' = ListMergeSort.sort op> (a # b)
(* Remove elements if they occur more than once. Flag indicates whether x
should be removed when no further matches are found *)
fun symDif' (x :: y :: xs) flag =
(case (x = y, flag) of
(* Element is not flagged for removal, so keep it *)
(false, false) => x :: symDif' (y :: xs) false
(* Reset the flag and remove x as it was marked for removal *)
| (false, true) => symDif' (y::xs) false
(* Remove y and flag x for removal if it wasn't already *)
| (true, _) => symDif' (x::xs) true)
| symDif' xs _ = xs
in
symDif' ab' false
end
However this is still kind of stupid. As the sorting function goes through all elements in the combined list, and thus it also ought to be the one that is "responsible" for removing duplicates.
This is homework that has been driving crazy for the last couple of days.
I got a list that I am applying a function to - pushing each element to the right if the element next to it is smaller then the previous one.
My function to pass over the list once and sort the head of the list:
sortEm lis#(x:y:xs) = if x > y then y: sortEm (x:xs) else lis
sortEm [x] = [x]
sortEm [] = []
myList (x:y:xs) = if x > y then sortEm lis else x:myList(y:xs)
myList [] = []
myList [x] = [x]
But my problem is that once that sortem has finished it returns either an empty list or a list containing one element, how would i design this the functional way?
I was thinking about foldl and some haskell magic to go along with that but currently I am stuck.
Thanks in advance
First of, your sortEm function name is misleading, it doesn't sort its argument list but inserts its head element into its tail. As it happens, there is an insert function already in Data.List module that inserts its first argument into the 2nd, so there's an equivalency
sortEm (x:xs) === Data.List.insert x xs
Now, inserting an item will only get you a sorted list back if you're inserting it into a list that is already sorted. Since empty list is sorted, that's what myList function does that you got in dave4420's answer. That is an "insertion" sort, progressively inserting elements of list into an auxiliary list, initially empty. And that's what the 2nd function does that you got in dave4420 answer:
insertionSort xs = foldr Data.List.insert [] xs
This does "apply sortem" i.e. inserts, "each element" only once. For a list [a,b,c,...,z] it's equivalent to
insert a (insert b (insert c (... (insert z []) ...)))
What you probably meant in your comment, i.e. comparing (and possibly swapping) two neighboring elements "only once", is known as bubble sort. Of course making only one pass through the list won't get it sorted, in a general case:
bubbleOnce xs = foldr g [] xs where
g x [] = [x]
g x xs#(y:ys) | x>y = y:x:ys -- swap x and y in the output
| otherwise = x:xs -- keep x before y in the output
Now, bubbleOnce [4,2,6,1,8] ==> [1,4,2,6,8]. The value that you expected, [2,4,1,6,8], would result from applying the folding function g in an opposite direction, from the left to the right. But that's much less natural to do here with Haskell lists:
bubbleOnce' [] = []
bubbleOnce' (x:xs) = let (z,h)=foldl g (x,id) xs in (h [z]) where
g (x,f) y | x>y = (x, f.(y:)) -- swap x and y in the output
| otherwise = (y, f.(x:)) -- keep x before y in the output
(edit:) see jimmyt's answer for the equivalent, but simple and nice version using straightforward recursion. It is also lazier (less strict) than both the fodlr and foldl versions here.
myList [] = []
myList (x : xs) = sortEm (x : myList xs)
(untested)
Or in terms of a fold:
myList = foldr cons []
where cons x xs = sortEm (x : xs)
(also untested)
-- if..then..else version
sortEM :: Ord a => [a] -> [a]
sortEM (x:y:xs) = if x < y
then x : sortEM (y:xs)
else y : sortEM (x:xs)
sortEM b = b
-- guard version
sortEM_G :: Ord a => [a] -> [a]
sortEM_G (x:y:xs)
| x < y = x : sortEM_G (y:xs)
| otherwise = y : sortEM_G (x:xs)
sortEM_G b = b
I need a program that checks if the difference between all pairs of elements is in the interval from -2 up to 2 ( >= -2 && < 2). If it is, then return True, else return False. Foe example, [1,2,3] is True, but [1,3,4] is False.
I am using the all function. What is wrong with my if clause?
allfunc (x : xs)
= if all (...) xs
then allfunc xs
else [x] ++ allfunc xs
allfunc _
= []
Or I am doing something completely wrong?
For this, it's probably easier to use list comprehensions or do-notation.
pairsOf lst = do
x <- lst
y <- lst
return (x, y)
pairsOf returns the list of pairs of numbers in the input lst. For example, pairsOf [1,2,3] results in [(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3)].
Now, you can define the difference between a pair in a one-liner \(x, y) -> x - y and map that over the list:
differences lst = map (\(x, y) -> x - y) (pairsOf lst)
Now you just have to make sure that each element in differences lst is between -2 and 2.
Of course, this is just one possible way to do it. There are many other ways as well.
The naive way to do what you describe is:
allfunc xs = all (<=2) [abs(a-b) | a <- xs, b <- xs ]
However, a more efficient method would be to compare the minimum and maximum of the list:
fastfunc [] = true
fastfunc xs = maximum xs - minimum xs <= 2
Why not simply...
allfunc xs = (maximum xs - minimum xs) <= 2
Or if you really want to investigate every pair, you can use monads:
import Control.Monad
allfunc xs = all ((<=2).abs) $ liftM2 (-) xs xs
liftA2 from Control.Applicative would do as well.
Well, the problem specification isn't very clear.
You say:
the diffence between all elements is in interval from -2 till 2 ( >= -2 && < 2)
But also:
Foe example, [1,2,3] is True, but [1,3,4] is False
How is it True for [1,2,3]?
Assuming you mean -2 <= diff <= 2, then I would use this:
allfunc :: (Ord a, Num a) => [a] -> Bool
allfunc theList = all (\x -> (x >= -2) && (x<2)) [x-y | x <- theList, y <- theList ]
allfunc [1,2,3] -- => True
allfunc [1,3,4] -- => False
Basically, yes you're doing something wrong. all is meant to take a predicate and a list of values to test. So it will return True if and only if all values yield true when applied to the given predicate function. I.e.:
allValuesEven = all even
allValuesOdd = all odd
My question is like the one here.
I'm working on a char list list and I need to check that 1-9 are used once in every list, but also once in every position in the list.
My code looks like this:
infix member
fun x member [] = false
| x member (y::ys) = x = y orelse x member ys;
fun rscheck xs =
let
val ys = [#"1",#"2",#"3",#"4",#"5",#"6",#"7",#"8",#"9"]
in
ys member xs
end;
but this only checks if 1-9 are members of the lists, not if they're on the same position in different lists.
I had the idea to use this function:
fun poslist xs n = map (fn x => List.nth (x , n)) xs;
(the function poslist is supposed to return whatever is in position n of the list xs, so I can isolate the individual lists in the char list list), but since poslist returns a char list rscheck can't work with it as it needs a char list list.
1) Can I improve poslist?
2) How do I fix rscheck?
Edit
infix member
fun x member [] = false
| x member (y::ys) = x = y orelse x member ys;
fun samelist (x::xs) ys = x member ys andalso samelist xs ys
| samelist [] _ = true;
fun takelist xs n = map (fn x => List.nth (x , n)) xs;
fun reverse xs = List.tabulate (9 , fn x => takelist xs x);
fun rscheck xs =
let
val s = [#"1",#"2",#"3",#"4",#"5",#"6",#"7",#"8",#"9"]
in
List.all (fn x => samelist s x) xs
end andalso rscheck (reverse xs);
Your rscheck method just checks whether one of the rows is equal to [#"1",#"2",#"3",#"4",#"5",#"6",#"7",#"8",#"9"]. What it should do is check that all the rows contain the numbers in any order. Once you fix that you can solve the rest of the problem as follows:
The easiest way to check whether a matrix is a valid sudoku solution is to use your rscheck function on it, then transpose it (i.e. switch its rows and columns) and then use your rscheck on the transposed matrix. If it returns true both times, it's a valid sudoku solution.
To transpose the matrix you can either translate this OCaml code to SML, or simply use your poslist function for all indices from 0 to 8.