I need to define a function largestPrefix that goes through a list of strings
and returns the longest prefix of two adjacent strings of the list in a tuple. The first element of the tuple is the length of the prefix .
a.e.: largestPrefix ["a","abca","bca","bcadabca","ca","cdabca"] => (3,"bca")
I have already built a function for two Stings, but have no idea how to use that on a list of lists. To ensure the adjacency I thought about using this:
prefix:: String -> String -> String
prefix (x:xs) (y:ys) | x:xs == "" = ""
| y:ys == "" = ""
| x == y = x:prefix xs ys
| otherwise = ""
So I cleaned up your function a bit and added the following idea:
if you write a function that applies an operator to every two consecutive pairs of a list (pairwise) then you should be able to finish your work:
pairwise :: (a -> a -> b) -> [a] -> [b]
pairwise f (x:xs#(y:_)) = f x y : pairwise f xs
pairwise _ _ = []
prefix:: String -> String -> String
prefix (x:xs) (y:ys)
| x == y = x:prefix xs ys
| otherwise = ""
prefix _ _ = ""
here is an example:
λ> pairwise prefix ["a","abca","bca","bcadabca","ca","cdabca"]
["a","","bca","","c"]
so maybe someone was unhappy because I did not resolve everything so here you go:
largestPrefix :: [String] -> (Int, String)
largestPrefix xs = maximumBy (compare `on` length . snd) $ zip [1..] (pairwise prefix xs)
where you have to import this to work:
import Data.List (maximumBy)
import Data.Function (on)
example
λ> largestPrefix ["a","abca","bca","bcadabca","ca","cdabca"]
(3,"bca")
Related
I'm trying to write a function with the type declaration [(Int, Bool)] -> [[Int]]. I want the function to only add Ints to the same nested sublist if the Boolean is True. However if the Boolean is False, I want the Int associated with the next True bool to be added to a new sublist. For example: An input of
[(1,True),(2,True),(3,False),(4,True),(5,False),(6,False),(7,True)]
should return
[[1,2],[4],[7]].
My code so far:
test:: [(Int, Bool)] -> [[Int]]
test xs = case xs of
[]->[]
x:xs
| snd x == True -> [(fst x)] : test xs
| snd x == False -> test xs
I'm currently having issues on adding concurrent Ints to the same list if their bools are both True.
You can break this problem into two sub-problems.
For any given list, take the head of this list and match it against the rest of list. There are two possibilities during this matching: i) You are successful i.e. you match, and if so, you collect the matched value and continue looking for more values, or ii) You fail, i.e. you don't match, and if so, you stop immediately and return the so far matched result with rest of, not-inspected, list.
collectF :: (Eq a) => (a -> Bool) -> [a] -> ([a], [a])
collectF f [] = ([], [])
collectF f (x : xs)
| f x = let (ys, zs) = collectF f xs in (x : ys, zs)
| otherwise = ([], x : xs)
Now that you have the collectF function, you can use it recursively on input list. In each call, you would get a successful list with rest of, not-inspected, list. Apply collectF again on rest of list until it is exhausted.
groupBy :: (Eq a) => (a -> a -> Bool) -> [a] -> [[a]]
groupBy _ [] = []
groupBy f (x : xs) =
let (ys, zs) = collectF (f x) xs in
(x : ys) : groupBy f zs
*Main> groupBy (\x y -> snd x == snd y) [(1,True),(2,True),(3,False),(4,True),(5,False),(6,False),(7,True)]
[[(1,True),(2,True)],[(3,False)],[(4,True)],[(5,False),(6,False)],[(7,True)]]
I am leaving it to you to remove the True and False values from List. Also, have a look at List library of Haskell [1]. Hope, I am clear enough, but let me know if you have any other question.
[1] http://hackage.haskell.org/package/base-4.12.0.0/docs/src/Data.OldList.html#groupBy
Repeatedly, drop the Falses, grab the Trues. With view patterns:
{-# LANGUAGE ViewPatterns #-}
test :: [(a, Bool)] -> [[a]]
test (span snd . dropWhile (not . snd) -> (a,b))
| null a = []
| otherwise = map fst a : test b
Works with infinite lists as well, inasmuch as possible.
Here's how I'd write this:
import Data.List.NonEmpty (NonEmpty(..), (<|))
import qualified Data.List.NonEmpty as NE
test :: [(Int, Bool)] -> [[Int]]
test = NE.filter (not . null) . foldr go ([]:|[])
where
go :: (Int, Bool) -> NonEmpty [Int] -> NonEmpty [Int]
go (n, True) ~(h:|t) = (n:h):|t
go (n, False) l = []<|l
Or with Will Ness's suggestion:
import Data.List.NonEmpty (NonEmpty(..))
test :: [(Int, Bool)] -> [[Int]]
test = removeHeadIfEmpty . foldr prependOrStartNewList ([]:|[])
where
prependOrStartNewList :: (Int, Bool) -> NonEmpty [Int] -> NonEmpty [Int]
prependOrStartNewList (n, True) ~(h:|t) = (n:h):|t
prependOrStartNewList (n, False) l = []:|removeHeadIfEmpty l
removeHeadIfEmpty :: NonEmpty [Int] -> [[Int]]
removeHeadIfEmpty (h:|t) = if null h then t else h:t
Basically I have this exercise: Recall the StudentMark type synonym from last week. Write a recursive function:
listMarks :: String -> [StudentMark] -> [Int]
which gives a list of the marks for a particular student; for example:
listMarks "Joe" [("Joe", 45), ("Sam", 70), ("Joe", 52)] = [45,52]
This was the way I wrote the function:
type StudentMark = (String, Int)
listMarks :: String -> [StudentMark] -> [Int]
listMarks _ [] = []
listMarks std (x:xs)
| std == fst x = snd x : listMarks (fst x) xs
| otherwise = listMarks (fst x) xs
This does not work if a string from the list is different from the "std" string. I would like to understand why and how could I make this work? Thank you!
Easy Fix
Just change the guard | otherwise = listMarks std xs. I would also change it in the guard above, as | std == fst x = snd x : listMarks std xs as yes, they are equal, but it makes it more clear what you want to achieve. so your code would be:
type StudentMark = (String, Int)
listMarks :: String -> [StudentMark] -> [Int]
listMarks _ [] = []
listMarks std (x:xs)
| std == fst x = snd x : listMarks std xs
| otherwise = listMarks std xs
Better Versions
As you can see, you ae calling the function with always the same first argument, so it's highly likely you can write a neater version. Here are two quick ideas:
List Comprehension
Personally my favourite, list comprehensions are very versitile and clear:
listMarks' :: String -> [StudentMark] -> [Int]
listMarks' str marks = [m |(n,m) <- marks, n==str]
Basically you filter the list based on the first element, and then you return the second one.
Higher Order Functions
With higher order functions map, filter and fold, you can do as much as recursion and lcs, but often looks tidier. You want to, again, filter the list based on the first element, and then you return the second one.
listMarks'' :: String -> [StudentMark] -> [Int]
listMarks'' str = map snd . filter (\(n,_) -> n == str)
I am trying to write a program that checks if the first list is a prefix of the second list. for example, [5,6] is prefix of [1,5,6,7]. here is my working code but basically I don't have an idea on how to do it.
prefix [Int] -> [Int] -> Bool
prefix [] [] = []
prefix y (x:xs)
| x == y = prefix y xs
| otherwise = 0
any help please ?
Your code does not make much sense if we look at the types:
prefix [Int] -> [Int] -> Bool
prefix [] [] = []
prefix y (x:xs)
| x == y = prefix y xs
| otherwise = 0
Since the two arguments are lists ([Int]), this thus means that y is an [Int], x is an Int, and xs is an [Int]. But then you compare x == y, you can not compare a list with an element. (==) is defined as (==) :: Eq a => a -> a -> Bool.
There are also other problems here: you return a list in the first clause, but the return type is a Bool, and later you return a 0 (again, it should be a Bool).
In case we define a function, we first need to define a certain model for it. When is a list l1 a prefix of a list l2? In case l1 is an empty list, then l1 is always a prefix, regardless of the value of the second list, so:
prefix [] _ = True
In case l1 is a list (i.e. (x:xs)), then it is not a prefix in two cases: (1) in case l2 is an empty list; and (2) in case the first item of l2 (y in (y:ys)) is not equal to x, so:
prefix _ [] = False
prefix (x:xs) (y:ys) | x /= y = False
| otherwise = ...
Now the question is what to do with prefix (x:xs) (y:ys) in case x == y. In that case we recurse on the two list, so the result of prefix (x:xs) (y:ys) == prefix xs ys (only in case x == y), so:
| otherwise = prefix xs ys
Or now in full:
prefix :: [Int] -> [Int] -> Bool
prefix [] _ = True
prefix _ [] = False
prefix (x:xs) (y:ys) | x /= y = False
| otherwise = prefix xs ys
We can further generalize the expression to Eq a => [a] -> [a] -> Bool such that it works with any type a that is an Eq instance (so there is a (==) instance defined over a):
prefix :: Eq a => [a] -> [a] -> Bool
prefix [] _ = True
prefix _ [] = False
prefix (x:xs) (y:ys) | x /= y = False
| otherwise = prefix xs ys
We can also swap the conditions, since usually positive logic is easier to understand than negative logic:
prefix :: Eq a => [a] -> [a] -> Bool
prefix [] _ = True
prefix _ [] = False
prefix (x:xs) (y:ys) | x == y = prefix xs ys
| otherwise = False
now we can furthermore remove the guards, and use an (&&) :: Bool -> Bool -> Bool instead:
prefix :: Eq a => [a] -> [a] -> Bool
prefix [] _ = True
prefix _ [] = False
prefix (x:xs) (y:ys) = x == y && prefix xs ys
Just leaving my two cents here with a combination of functions from Prelude:
isPrefix :: Eq a => [a] -> [a] -> Bool
isPrefix l1 l2 = take (length l1) l2 == l1
I've written a function that will compare two lists and check to see if the first is a prefix of the second and it must be done using recursion.
For example:
prefix [1,2] [1,2,3]
>True
prefix [2,1,4] [2,1,13,4]
>False
Now I've done this but I feel it's inefficient:
prefix :: [Int] -> [Int] -> Bool
prefix (x:xs) (y:ys)
| null xs = True
| x == y && head xs == head ys = True && prefix xs ys
| head xs /= head ys = False
I was hoping it could be done more efficiently and with some better pattern matching. Can it be?
You don't need to use the head function at all. That doubles the number of comparisons. Try this:
prefix :: [Int] -> [Int] -> Bool
prefix [] _ = True
prefix _ [] = False
prefix (x:xs) (y:ys)
| x == y = prefix xs ys
| otherwise = False
Chad Gilbert's solution can be streamlined very slightly:
prefix :: [Int] -> [Int] -> Bool
prefix [] _ = True
prefix (x:xs) (y:ys)
| x == y = prefix xs ys
prefix _ _ = False
This won't affect the performance, but it demonstrates a language feature: when all the guards on a pattern fail, that match will be abandoned and matching will resume with the next pattern.
Prelude > let prefix [] _ = True
Prelude | prefix _ [] = False
Prelude | prefix (x:xs) (y:ys) = if ( x==y) then prefix xs ys else False
Examples:
Prelude> prefix [1,3] []
False
Prelude> prefix [] [1,2,3]
True
Prelude> prefix [1,2] [1,2,3]
True
Is there a Haskell function that takes a list and returns a list of duplicates/redundant elements in that list?
I'm aware of the the nub and nubBy functions, but they remove the duplicates; I would like to keep the dupes and collects them in a list.
The simplest way to do this, which is extremely inefficient, is to use nub and \\:
import Data.List (nub, (\\))
getDups :: Eq a => [a] -> [a]
getDups xs = xs \\ nub xs
If you can live with an Ord constraint, everything gets much nicer:
import Data.Set (member, empty, insert)
getDups :: Ord a => [a] -> [a]
getDups xs = foldr go (const []) xs empty
where
go x cont seen
| member x seen = x : r seen
| otherwise = r (insert x seen)
I wrote these functions which seems to work well.
The first one return the list of duplicates element in a list with a basic equlity test (==)
duplicate :: Eq a => [a] -> [a]
duplicate [] = []
duplicate (x:xs)
| null pres = duplicate abs
| otherwise = x:pres++duplicate abs
where (pres,abs) = partition (x ==) xs
The second one make the same job by providing a equality test function (like nubBy)
duplicateBy :: (a -> a -> Bool) -> [a] -> [a]
duplicateBy eq [] = []
duplicateBy eq (x:xs)
| null pres = duplicateBy eq abs
| otherwise = x:pres++duplicateBy eq abs
where (pres,abs) = partition (eq x) xs
Is there a Haskell function that takes a list and returns a list of duplicates/redundant elements in that list?
You can write such a function yourself easily enough. Use a helper function that takes two list arguments, the first one of which being the list whose dupes are sought; walk along that list and accumulate the dupes in the second argument; finally, return the latter when the first argument is the empty list.
dupes l = dupes' l []
where
dupes' [] ls = ls
dupes' (x:xs) ls
| not (x `elem` ls) && x `elem` xs = dupes' xs (x:ls)
| otherwise = dupes' xs ls
Test:
λ> dupes [1,2,3,3,2,2,3,4]
[3,2]
Be aware that the asymptotic time complexity is as bad as that of nub, though: O(n^2). If you want better asymptotics, you'll need an Ord class constraint.
If you are happy with an Ord constraint you can use group from Data.List:
getDups :: Ord a => [a] -> [a]
getDups = concatMap (drop 1) . group . sort