Related
I'm trying to make it so that on a tuple input (n,m) and a list of tuples xs , if the first item in the tuple in xs is in (n,m) then keep it that way in the new list otherwise add the a tuple consisting of some value k from n to m as a first element and as second element it should be 0.My question is:how can i say "repeat 0" using guards ? Since clearly my code won't run since my code says "repeat = 0"
expand :: (Int,Int) -> Profile ->Profile
expand (n,m) [] = zip [n..m] (repeat 0)
expand (n,m) (x:xs) = zip [n..m] (repeat (|(fst (x) `elem` [n..m]) == False = 0
|otherwise = snd (x))
You can use a helper function here that converts a number in the [ n .. m ] range to a 2-tuple. Here we thus try to find an element in the list xs that matches with the first item of that tuple, if we do not find such element, we use 0:
import Data.List(find)
expand :: (Int,Int) -> Profile -> Profile
expand (n,m) xs = map go [n .. m]
where go i | Just l <- find (\(f, _) -> f == i) xs = l
| otherwise = (i, 0)
For a list, find was implemented as [src]:
find :: (a -> Bool) -> [a] -> Maybe a
find p = listToMaybe . filter p
filter thus will make a list that contains the elements that satisfy the predicate p, and listToMaybe :: [a] -> Maybe a will convert an empty list [] to Nothing, and for a non-empty list (x:_) it will wrap the first element x in a Just data constructor. Due to Haskell's laziness, it will thus look for the first element that satisfies the predicate.
this thus gives us:
Prelude Data.List> expand (2,7) [(4, 2.3), (6, 3)]
[(2,0.0),(3,0.0),(4,2.3),(5,0.0),(6,3.0),(7,0.0)]
Hey guys I have a question about matching lists
Given the list of lists:
Input List 1 = [[True],[False],[True],[[False]]
Input List 2 = [[Bob],[Rick],[Lee],[Bill]]
Input List 3 = [[1],[2],[3],[4]]
Then match the Booleans of list 1 with the other lists so this happens:
Input List 1 + Input List 2 = [[Bob],[Dead],[Lee],[Dead]]
Input List 1 + Input List 2 = [[1],[0],[3],[0]]
As far as I can see, using nested lists here is unnecessary. Without them, all you need is zipWith and an appropriate combining function:
-- The first argument is the "dead" value. Note that this works with any type.
makeDead :: a -> Bool -> a -> a
makeDead dead b val
| b = val
| otherwise = dead
GHCi> :t zipWith
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
GHCi> zipWith (makeDead "Dead") [True,False,True,False] ["Bob","Rick","Lee","Bill"]
["Bob","Dead","Lee","Dead"]
Two variations on the theme. Firstly, if whether a value should be changed depends only on what the value is, then you can simply use map/fmap:
-- Affects all names with 'i' as the second letter:
lethalLetter :: String -> String
lethalLetter name -> case name of
(_:'i':_) -> "Dead"
_ -> name
GHCi> fmap lethalLetter ["Bob", "Rick", "Lee", "Bill"]
["Bob","Dead","Lee","Dead"]
Secondly, you might prefer using Maybe to indicate deadness rather than using an arbitrary value (what if someone is actually called "Dead")?
makeDead' :: Bool -> a -> Maybe a
makeDead' b val
| b = Just val
| otherwise = Nothing
GHCi> zipWith makeDead' [True,False,True,False] ["Bob","Rick","Lee","Bill"]
[Just "Bob",Nothing,Just "Lee",Nothing]
You can then use functions like maybe, fromMaybe and catMaybes (the latter two are in Data.Maybe) to get rid of the Nothings however you feel like doing it:
GHCi> import Data.Maybe
GHCi> foo = zipWith makeDead' [True,False,True,False] ["Bob","Rick","Lee","Bill"]
GHCi> catMaybes foo
["Bob","Lee"]
Assuming you change them to lists, as recommended by duplode, how about zipping together the two lists within a list comprehension, something like this:
[if flag then val else defaultVal | (flag, val) <- zip(list1, list2)]
where defaultVal would have to be specified, but seems to be Dead and 0 for lists 2 and 3.
(I don't have access right now to Haskell, so the syntax may not be 100% there, but that's the idea.)
You can use zipWith . zipWith :: (a -> b -> c) -> [[a]] -> [[b]] -> [[c]] for matching lists of lists. For example:
import Data.Bool (bool)
kill deadVal = zipWith . zipWith $ bool (const deadVal) id
example = kill 0 [[True, False],[False,True]] [[1,2,3],[2]]
-- example = [[1,0],[0]]
Given a list like:
[1, 2, 2, 6, 7, 8, 10, 11, 12, 15]
Split it into blandly increasing ranges (maybe equal):
[[1, 2, 2], [6, 7, 8], [10, 11, 12], [15]]
I tried using a recursive approach:
splitRanges [] = [[]]
splitRanges (x:y:xs)
| x `elem` [y, y + 1] = [x, y] : splitRanges xs
| otherwise = xs
So if the item is one less or equal to the item after I fuse them. But it says I am trying to build an infinite type:
Occurs check: cannot construct the infinite type: a0 = [a0]
Expected type: [[a0]]
Actual type: [a0]
But what does [the fact that it is monotone] have to do with how the list is split?
That being strictly increasing would give different results.
Or are you really trying to say something else?
I hope I am not.
Will the list always be monotone?
No, splitting a monotone list means making it into just one sub-list.
If not, how should that affect the results?
If it is not monotone, you will have many sublists.
Is it always brown into groups of three?
No, the groups may contain n elements.
More examples would be good
splitRanges [1, 3] == [[1], [3]]
splitRanges [1, 2, 5] == [[1, 2], [3]]
splitRanges [0, 0, 1] == [[0, 0, 1]]
splitRanges [1, 5, 7, 9] == [[1], [5], [7], [9]]
I appreciate hints rather than full answers, as I would like to improve myself, copy-pasting is not improvement.
Try breaking the problem into more manageable parts.
First, how would you split just one blandly increasing range from the start of a list? Lets guess that should be splitOne :: [Integer] -> ([Integer], [Integer]).
Second, how can you repeatedly apply splitOne to the left-over list? Try implementing splitMany :: [Integer] -> [[Integer]] by using splitOne.
For splitOne, what should you be trying to find? The first position to split at. What are "split positions"? Lets make that up.
split 0 1 2 3 4 …
list [ | x1, | x2, | x3, | x4, | x5, …]
So a split at 0 is ([], [x1,x2,x3,x4,x5,…]), and a split at 3 is ([x1,x2,x3],[x4,x5,…]). What relationship can you see between the split position and the split list?
How do you determine the first split position of the list? Lets say that is implemented as firstSplitPos :: [Integer] -> Integer. What is the first split position of an empty list?
Can you now implement splitOne using firstSplitPos?
One Possible Answer
-- What are the adjacencies for:
-- 1) empty lists?
-- 2) lists with one element?
-- 3) lists with more than one element?
--
-- Bonus: rewrite in point-free form using <*>
--
adjacencies :: [a] -> [(a,a)]
adjacencies xxs = zip xxs (drop 1 xxs)
-- Bonus: rewrite in point-free form
--
withIndices :: [a] -> [(Int,a)]
withIndices xxs = zip [0..] xxs
-- This is the most involved part of the answer. Pay close
-- attention to:
-- 1) empty lists
-- 2) lists with one element
-- 3) lists which are a blandly increasing sequence
--
firstSplitPos :: (Eq a, Num a) => [a] -> Int
firstSplitPos xxs = maybe (length xxs) pos (find q searchList)
where q (_,(a,b)) = a /= b && a + 1 /= b
searchList = withIndices (adjacencies xxs)
-- Why is the split position one more than the index?
pos (i,_) = i + 1
--
-- Bonus: rewrite in point-free form using <*>
--
splitOne :: (Eq a, Num a) => [a] -> ([a],[a])
splitOne xxs = splitAt (firstSplitPos xxs) xxs
splitMany :: (Eq a, Num a) => [a] -> [[a]]
-- What happens if we remove the case for []?
splitMany [] = []
splitMany xxs = let (l, r) = splitOne xxs in l : splitMany r
Another Approach
This is my explanation of Carsten's solution. It is already succinct but I have elected for a variation which does not use a 2-tuple.
We know that Haskell lists are defined inductively. To demonstrate this, we can define an equivalent data type.
data List a = Cons a (List a) -- Cons = (:)
| Nil -- Nil = []
Then ask the question: can we use induction on lists for the solution? If so, we only have to solve two cases: Cons and Nil. The type signature of foldr shows us exactly that:
foldr :: (a -> b -> b) -- Cons case
-> b -- Nil case
-> [a] -- The list
-> b -- The result
What if the list is Nil? Then the only blandly increasing sequence is the empty sequence. Therefore:
nilCase = [[]]
We might want nilCase = [] instead, as that also seems reasonable — i.e. there are no blandly increasing sequences.
Now you need some imagination. In the Cons case we only get to look at one new element at a time. With this new element, we could decide whether it belongs to the right-adjacent sequence or if it begins a new sequence.
What do I mean by right-adjacent? In [5,4,1,2,2,7], 1 belongs to the right-adjacent sequence [2,2].
How might this look?
-- The rest of the list is empty
consCase new [] = [new] : []
-- The right-adjacent sequence is empty
consCase new ([]:ss) = [new] : ss
-- The right-adjacent sequence is non-empty
-- Why `new + 1 == x` and not `new == x + 1`?
consCase new sss#(xxs#(x:_):ss)
| new == x || new + 1 == x = (new:xxs):ss
| otherwise = [new]:sss
Now that we solved the Nil case and the Cons case, we are done!
splitRanges = foldr consCase nilCase
It would be useful and idiomatic to write your function to take a predicate, instead of writing your split condition into the function itself:
splitBy2 :: (a -> a -> Bool) -> [a] -> [[a]]
splitBy2 ok xs = snd $ f xs [] []
where f (a:b:xs) acc_list acc_out_lists | ok a b = ...
I hope you don't mind spoiling part of it, but as the comments are discussing what you want (and I hope I've got it) maybe you are interested in another possible solution?
I don't want to spoil it all but I think you can easily work this out:
blandly :: (Ord a, Num a) => [a] -> [[a]]
blandly = g . foldr f ([],[])
where f x ([],xss) = ([x],xss)
f x (y:ys,xss)
| abs (x-y) <= 1 = undefined
| otherwise = undefined
g (ys,xss) = undefined
you just have to fill in the undefined holes
The idea is just to fold the list from the right, accumulating your inner lists in the first item of the tuple, s long as the elements are not to far away; and if they are: to push it to the second item.
If done correctly it will yield:
λ> blandly [1,3]
[[1],[3]]
λ> blandly [1,2,5]
[[1,2],[5]]
λ> blandly [0,0,1]
[[0,0,1]]
λ> blandly [1,5,7,9]
[[1],[5],[7],[9]]
which seems to be what you want
1 hour later - I think I can post my solution - just stop reading if you don't want to get spoiled
blandly :: (Ord a, Num a) => [a] -> [[a]]
blandly = uncurry (:) . foldr f ([],[])
where f x ([],xs) = ([x],xs)
f x (y:ys,xs)
| abs (x-y) <= 1 = (x:y:ys,xs)
| otherwise = ([x],(y:ys):xs)
maybe I have a slight misunderstanding here (the examples did not specify it) - but if you want on only monotonic increasing inner lists you just have to change the abs part:
blandly :: (Ord a, Num a) => [a] -> [[a]]
blandly = uncurry (:) . foldr f ([],[])
where f x ([],xss) = ([x],xss)
f x (y:ys,xss)
| 0 <= y-x
&& y-x <= 1 = (x:y:ys,xss)
| otherwise = ([x],(y:ys):xss)
I am teaching myself Haskell and have run into a problem and need help.
Background:
type AInfo = (Char, Int)
type AList = [AInfo] (let’s say [(‘a’, 2), (‘b’,5), (‘a’, 1), (‘w’, 21)]
type BInfo = Char
type BList = [BInfo] (let’s say [‘a’, ‘a’, ‘c’, ‘g’, ‘a’, ‘w’, ‘b’]
One quick edit: The above information is for illustrative purposes only. The actual elements of the lists are a bit more complex. Also, the lists are not static; they are dynamic (hence the uses of the IO monad) and I need to keep/pass/"return"/have access to and change the lists during the running of the program.
I am looking to do the following:
For all elements of AList check against all elements of BList and where the character of the AList element (pair) is equal to the character in the Blist add one to the Int value of the AList element (pair) and remove the character from BList.
So what this means is after the first element of AList is checked against all elements of BList the values of the lists should be:
AList [(‘a’, 5), (‘b’,5), (‘a’, 1), (‘w’, 21)]
BList [‘c’, ‘g’, ‘w’, ‘b’]
And in the end, the lists values should be:
AList [(‘a’, 5), (‘b’,6), (‘a’, 1), (‘w’, 22)]
BList [‘c’, ‘g’]
Of course, all of this is happening in an IO monad.
Things I have tried:
Using mapM and a recursive helper function. I have looked at both:
Every element of AList checked against every element of bList -- mapM (myHelpF1 alist) blist and
Every element of BList checked against every element of AList – mapM (myHelpF2 alist) blist
Passing both lists to a function and using a complicated
if/then/else & helper function calls (feels like I am forcing
Haskell to be iterative; Messy convoluted code, Does not feel
right.)
I have thought about using filter, the character value of AList
element and Blist to create a third list of Bool and the count the
number of True values. Update the Int value. Then use filter on
BList to remove the BList elements that …… (again Does not feel
right, not very Haskell-like.)
Things I think I know about the problem:
The solution may be exceeding trivial. So much so, the more experienced Haskellers will be muttering under their breath “what a noob” as they type their response.
Any pointers would be greatly appreciated. (mutter away….)
A few pointers:
Don't use [(Char, Int)] for "AList". The data structure you are looking for is a finite map: Map Char Int. Particularly look at member and insertWith. toList and fromList convert from the representation you currently have for AList, so even if you are stuck with that representation, you can convert to a Map for this algorithm and convert back at the end. (This will be more efficient than staying in a list because you are doing so many lookups, and the finite map API is easier to work with than lists)
I'd approach the problem as two phases: (1) partition out the elements of blist by whether they are in the map, (2) insertWith the elements which are already in the map. Then you can return the resulting map and the other partition.
I would also get rid of the meaningless assumptions such as that keys are Char -- you can just say they are any type k (for "key") that satisfies the necessary constraints (that you can put it in a Map, which requires that it is Orderable). You do this with lowercase type variables:
import qualified Data.Map as Map
sieveList :: (Ord k) => Map.Map k Int -> [k] -> (Map.Map k Int, [k])
Writing algorithms in greater generality helps catch bugs, because it makes sure that you don't use any assumptions you don't need.
Oh, also this program has no business being in the IO monad. This is pure code.
import Data.List
type AInfo = (Char, Int)
type AList = [AInfo]
type BInfo = Char
type BList = [BInfo]
process :: AList -> BList -> AList
process [] _ = []
process (a:as) b = if is_in a b then (fst a,snd a + 1):(process as (delete (fst a) b)) else a:process as b where
is_in f [] = False
is_in f (s:ss) = if fst f == s then True else is_in f ss
*Main> process [('a',5),('b',5),('a',1),('b',21)] ['c','b','g','w','b']
[('a',5),('b',6),('a',1),('b',22)]
*Main> process [('a',5),('b',5),('a',1),('w',21)] ['c','g','w','b']
[('a',5),('b',6),('a',1),('w',22)]
Probably an important disclaimer: I'm rusty at Haskell to the point of ineptness, but as a relaxing midnight exercise I wrote this thing. It should do what you want, although it doesn't return a BList. With a bit of modification, you can get it to return an (AList,BList) tuple, but methinks you'd be better off using an imperative language if that kind of manipulation is required.
Alternately, there's an elegant solution and I'm too ignorant of Haskell to know it.
While I am by no means a Haskell expert, I have a partial attempt that returns that result of an operation once. Maybe you can find out how to map it over the rest to get your solution. The addwhile is clever, since you only want to update the first occurrence of an element in lista, if it exists twice, it will just add 0 to it. Code critiques are more than welcome.
import Data.List
type AInfo = (Char, Int)
type AList = [AInfo]
type BInfo = Char
type BList = [BInfo]
lista = ([('a', 2), ('b',5), ('a', 1), ('w', 21)] :: AList)
listb = ['a','a','c','g','a','w','b']
--step one, get the head, and its occurrences
items list = (eleA, eleB) where
eleA = length $ filter (\x -> x == (head list)) list
eleB = head list
getRidOfIt list ele = (dropWhile (\x -> x == ele) list) --drop like its hot
--add to lista
addWhile :: [(Char, Int)] -> Char -> Int -> [(Char,Int)]
addWhile [] _ _ = []
addWhile ((x,y):xs) letter times = if x == letter then (x,y+times) : addWhile xs letter times
else (x,y) : addWhile xs letter 0
--first answer
firstAnswer = addWhile lista (snd $ items listb) (fst $ items listb)
--[('a',5),('b',5),('a',1),('w',21)]
The operation you describe is pure, as #luqui points out, so we just define it as a pure Haskell function. It can be used inside a monad (including IO) by means of fmap (or do).
import Data.List
combine alist blist = (reverse a, b4) where
First we sort and count the B list:
b = map (\g->(head g,length g)) . group . sort $ blist
We need the import for group and sort to be available. Next, we roll along the alist and do our thing:
(a,b2) = foldl g ([],b) alist
g (acc,b) e#(x,c) = case pick x b of
Nothing -> (e:acc,b)
Just (n,b2) -> ((x,c+n):acc,b2)
b3 = map fst b2
b4 = [ c | c <- blist, elem c b3 ]
Now pick, as used, must be
pick x [] = Nothing
pick x ((y,n):t)
| x==y = Just (n,t)
| otherwise = case pick x t of Nothing -> Nothing
Just (k,r) -> Just (k, (y,n):r)
Of course pick performs a linear search, so if performance (speed) becomes a problem, b should be changed to allow for binary search (tree etc, like Map). The calculation of b4 which is filter (`elem` b3) blist is another potential performance problem with its repeated checks for presence in b3. Again, checking for presence in trees is faster than in lists, in general.
Test run:
> combine [('a', 2), ('b',5), ('a', 1), ('w', 21)] "aacgawb"
([('a',5),('b',6),('a',1),('w',22)],"cg")
edit: you probably want it the other way around, rolling along the blist while updating the alist and producing (or not) the elements of blist in the result (b4 in my code). That way the algorithm will operate in a more local manner on long input streams (that assuming your blist is long, though you didn't say that). As written above, it will have a space problem, consuming the input stream blist several times over. I'll keep it as is as an illustration, a food for thought.
So if you decide to go the 2nd route, first convert your alist into a Map (beware the duplicates!). Then, scanning (with scanl) over blist, make use of updateLookupWithKey to update the counts map and at the same time decide for each member of blist, one by one, whether to output it or not. The type of the accumulator will thus have to be (Map a Int, Maybe a), with a your element type (blist :: [a]):
scanl :: (acc -> a -> acc) -> acc -> [a] -> [acc]
scanning = tail $ scanl g (Nothing, fromList $ reverse alist) blist
g (_,cmap) a = case updateLookupWithKey (\_ c->Just(c+1)) a cmap of
(Just _, m2) -> (Nothing, m2) -- seen before
_ -> (Just a, cmap) -- not present in counts
new_b_list = [ a | (Just a,_) <- scanning ]
last_counts = snd $ last scanning
You will have to combine the toList last_counts with the original alist if you have to preserve the old duplicates there (why would you?).
I am new to Haskell and I have the following problem. I have to create a list of numbers [f1, f2, f3...] where fi x = x ^ i. Then I have to create a function that applies the fi to a list of numbers. For example if I have a list lis = [4,5,6,7..] the output would be [4^1, 5^2,6^3, 7^4...]. This is what I have written so far :
powers x= [x^y |y<-[1,2,3,4]]
list = [1,2,3,4]
match :: (x -> xs) -> [x] -> [xs]
match f [] = []
match f (x:xs) = (f x) : ( match f xs )
So if I put the list = [1,2,3] the output is [1,1,1,1][2,4,8,16],[3,9,27,81] instead of [1,4,27]
Can you please tell me what is wrong and point me to the right direction?
The first issue is that powers is of type Int -> [Int]. What you really want, I think, is something of type [Int -> Int] -- a list of Int -> Int functions instead of a function that takes an Int and returns a list of Int. If you define powers like so:
powers = [(^y) | y <- [1..4]]
you can use zipWith to apply each power to its corresponding element in the list, like so:
zipWith ($) powers [1,2,3] -- returns [1,4,27]
The ($) applies its left (first) argument to its right (second) argument.
Note that using powers as defined here will limit the length of the returned list to 4. If you want to be able to use arbitrary length lists, you want to make powers an infinite list, like so:
powers = [(^y) | y <- [1..]]
Of course, as dave4420 points out, a simpler technique is to simply use
zipWith (^) [1,2,3] [1..] -- returns [1,4,27]
Your match is the standard function map by another name. You need to use zipWith instead (which you can think of as mapping over two lists side-by-side).
Is this homework?
You are currently creating a list for every input value.
What you need to do is recursively compute the appropriate
power for each input value, like this:
match f [] = []
match f (x:xs) y = (f x y) : (match f xs y+1)
Then, you can call this as match pow [1, 2, 3] 1.
This is equivalent to using zipWith and providing the desired function (pow), your input list ([1, 2, 3]) and the exponent list (a lazy one to infinity list) as arguments.