Related
if list1 = [14,24,1,2,11,7,23,8,12,22,20,0,15,19,4,9,10,21,18,17,3,13,16,5,6,25],
and list2 = [14,14,24,24,1,1,2,2]
How could I return a int list which is [0,0,1,1,2,2,3,3]
I have used the function
elemIndex' :: Eq a => a -> [a] -> Int
elemIndex' x = fromMaybe (-1) . elemIndex x
and the result for this for the first one
0
to get the index from list 1 for a single digit
But what I want is
findIndex :: [Int] -> [Int] -> [Int]
That would input two int list and return the index value base on the key list
How could I recursively get the index for one list or using any import function, such as map.
You've done a very good job of breaking the problem down. You've already recognized that you're doing the same thing for each element of the second list, and you've written a function to capture that behavior.
elemIndex' :: Eq a => a -> [a] -> Int
elemIndex' x = fromMaybe (-1) . elemIndex x
Now you want to take this function and apply it to each element of another list, collecting the results into a new list. That is, you want something that looks like
mystery :: (a -> b) -> [a] -> [b]
And we can search Hoogle and find exactly that function: map
map :: (a -> b) -> [a] -> [b]
map takes a function and a list and applies it to each element. You've got a function (elemIndex', with appropriate partial application), and you've got a list (list2 in your example). So let's put it together.
findAll :: Eq a => [a] -> [a] -> [Int]
findAll haystack needles = map (\x -> elemIndex' x haystack) needles
There are lots of streaming functions in Haskell like map, and knowing / figuring out which one to use in a given situation comes with practice. If you're ever in doubt, remember that you can use Hoogle to search for a type or you can simply do whatever you're trying to do recursively (if you didn't know map existed, you could write it yourself with a bit of recursion), and you'll get the hang of it over time. Good luck in your Haskell endeavors!
As an alternative to the answer by #SilvioMayolo, you could use a Map data structure. We zip in the indexes for each value in list1 and then turn that into a map, then just do a lookup for each value in list2.
import Data.Map
import Data.List
list1 = [14,24,1,2,11,7,23,8,12,22,20,0,15,19,4,9,10,21,18,17,3,13,16,5,6,25]
list2 = [14,14,24,24,1,1,2,2]
map1 = Data.Map.fromList $ list1 `zip` [0..]
-- fromList [(0,11),(1,2),(2,3),(3,20),(4,14),(5,23),(6,24),
-- (7,5),(8,7),(9,15),(10,16),(11,4),(12,8),(13,21),
-- (14,0),(15,12),(16,22),(17,19),(18,18),(19,13),
-- (20,10),(21,17),(22,9),(23,6),(24,1),(25,25)]
list3 = Data.List.map (map1 !) list2
-- [0,0,1,1,2,2,3,3]
I'm fairly new to Haskell and don't understand the following divide and conquer construct:
{- trivial solve split combine input/output-}
dc :: (a -> Bool) -> (a -> b) -> (a -> [a]) -> ([b] -> b) -> a -> b
dc trivial solve split combine = x
where
x y = if trivial y then solve y
else (\_ z -> combine z) y (map x (split y))
Now I need to implement a merge-sort function based on this construct. I tried to implement some functions but I'm pretty sure that's not how it should work:
trivial :: (Ord a, Num a) => [a] -> Bool
trivial [] = True
trivial (x:[]) = True
trivial (x:x':xs) = if x<=x' then trivial (x':xs) else False
split :: [a] -> [[a]]
split (x:[]) = [[x]]
split (x:xs) = [x] : split xs
combine :: [[a]] -> [a]
combine [[]] = []
combine ([]:ys) = combine ys
combine ((x:xs):ys) = x : combine (xs:ys)
So how does the construct above work ? What does "x" and "y" stand for ? What should "trivial" and "solve" (and split/combine) do ?
So, the signature of dc can be read as "this function takes 4 arguments and returns a function from a to b". In the definition, this function is called x. x is defined in the where clause, as:
x y = if trivial y then solve y
else (\_ z -> combine z) y (map x (split y))
You could add a type signature for x:
x :: a -> b
The definition of x (which is the function that performs your actual divide and conquer computation) is somewhat obfuscated, but can be read as:
If x is a trivial case, just solve it
Otherwise, split it, divide-and-conquer it (with x), then combine the result.
Note: It could be written a bit more clearly as:
x y = if trivial y then solve y
else (combine . map x . split) y
This function does all the recursivity you need, so your functions don't need to care about that. Your functions should be:
trivial: True if the problem can be solved with solve in this case. For the merge sort, the trivial case is the list that contains only one item.
solve: solves the trivial case. For the merge sort, it's just the identity (since it's just a one item list).
split: split the big problem into smaller problems (which will be done many times, until they are trivial. For the merge sort, it's just about splitting the list in half.
combine: takes a list of stuff that were previously splitted, and combine them. For the merge sort, that's where the merging magic happens :)
Note: the merge sort algorithm can be a bit different from what I mentioned. For example, a sorted list can also be a trivial case.
isTogether' :: String -> Bool
isTogether' (x:xs) = isTogether (head xs) (head (tail xs))
For the above code, I want to go through every character in the string. I am not allowed to use recursion.
isTogether' (x:xs) = isTogether (head xs) (head (tail xs))
If I've got it right, you are interested in getting consequential char pairs from some string. So, for example, for abcd you need to test (a,b), (b,c), (c,d) with some (Char,Char) -> Bool or Char -> Char -> Bool function.
Zip could be helpful here:
> let x = "abcd"
> let pairs = zip x (tail x)
it :: [(Char, Char)]
And for some f :: Char -> Char -> Bool function we can get uncurry f :: (Char, Char) -> Bool.
And then it's easy to get [Bool] value of results with map (uncurry f) pairs :: [Bool].
In Haskell, a String is just a list of characters ([Char]). Thus, all of the normal higher-order list functions like map work on strings. So you can use whichever higher-order function is most applicable to your problem.
Note that these functions themselves are defined recursively; in fact, there is no way to go through the entire list in Haskell without either recursing explicitly or using a function that directly or indirectly recurses.
To do this without recursion, you will need to use a higher order function or a list comprehension. I don't understand what you're trying to accomplish so I can only give generic advice. You probably will want one of these:
map :: (a -> b) -> [a] -> [b]
Map converts a list of one type into another. Using map lets you perform the same action on every element of the list, given a function that operates on the kinds of things you have in the list.
filter :: (a -> Bool) -> [a] -> [a]
Filter takes a list and a predicate, and gives you a new list with only the elements that satisfy the predicate. Just with these two tools, you can do some pretty interesting things:
import Data.Char
map toUpper (filter isLower "A quick test") -- => "QUICKTEST"
Then you have folds of various sorts. A fold is really a generic higher order function for doing recursion on some type, so using it takes a bit of getting used to, but you can accomplish pretty much any recursive function on a list with a fold instead. The basic type of foldr looks like this:
foldr :: (a -> b -> b) -> b -> [a] -> b
It takes three arguments: an inductive step, a base case and a value you want to fold. Or, in less mathematical terms, you could think of it as taking an initial state, a function to take the next item and the previous state to produce the next state, and the list of values. It then returns the final state it arrived at. You can do some pretty surprising things with fold, but let's say you want to detect if a list has a run of two or more of the same item. This would be hard to express with map and filter (impossible?), but it's easy with recursion:
hasTwins :: (Eq a) => [a] -> Bool
hasTwins (x:y:xs) | x == y = True
hasTwins (x:y:xs) | otherwise = hasTwins (y:xs)
hasTwins _ = False
Well, you can express this with a fold like so:
hasTwins :: (Eq a) => [a] -> Bool
hasTwins (x:xs) = snd $ foldr step (x, False) xs
where
step x (prev, seenTwins) = (x, prev == x || seenTwins)
So my "state" in this fold is the previous value and whether we've already seen a pair of identical values. The function has no explicit recursion, but my step function passes the current x value along to the next invocation through the state as the previous value. But you don't have to be happy with the last state you have; this function takes the second value out of the state and returns that as the overall return value—which is the boolean whether or not we've seen two identical values next to each other.
The question is to compute the mode (the value that occurs most frequently) of a sorted list of integers.
[1,1,1,1,2,2,3,3] -> 1
[2,2,3,3,3,3,4,4,8,8,8,8] -> 3 or 8
[3,3,3,3,4,4,5,5,6,6] -> 3
Just use the Prelude library.
Are the functions filter, map, foldr in Prelude library?
Starting from the beginning.
You want to make a pass through a sequence and get the maximum frequency of an integer.
This sounds like a job for fold, as fold goes through a sequence aggregating a value along the way before giving you a final result.
foldl :: (a -> b -> a) -> a -> [b] -> a
The type of foldl is shown above. We can fill in some of that already (I find that helps me work out what types I need)
foldl :: (a -> Int -> a) -> a -> [Int] -> a
We need to fold something through that to get the value. We have to keep track of the current run and the current count
data BestRun = BestRun {
currentNum :: Int,
occurrences :: Int,
bestNum :: Int,
bestOccurrences :: Int
}
So now we can fill in a bit more:
foldl :: (BestRun -> Int -> BestRun) -> BestRun -> [Int] -> BestRun
So we want a function that does the aggregation
f :: BestRun -> Int -> BestRun
f (BestRun current occ best bestOcc) x
| x == current = (BestRun current (occ + 1) best bestOcc) -- continuing current sequence
| occ > bestOcc = (BestRun x 1 current occ) -- a new best sequence
| otherwise = (BestRun x 1 best bestOcc) -- new sequence
So now we can write the function using foldl as
bestRun :: [Int] -> Int
bestRun xs = bestNum (foldl f (BestRun 0 0 0 0) xs)
Are the functions filter, map, foldr in Prelude library?
Stop...Hoogle time!
Did you know Hoogle tells you which module a function is from? Hoolging map results in this information on the search page:
map :: (a -> b) -> [a] -> [b]
base Prelude, base Data.List
This means map is defined both in Prelude and in Data.List. You can hoogle the other functions and likewise see that they are indeed in Prelude.
You can also look at Haskell 2010 > Standard Prelude or the Prelude hackage docs.
So we are allowed to map, filter, and foldr, as well as anything else in Prelude. That's good. Let's start with Landei's idea, to turn the list into a list of lists.
groupSorted :: [a] -> [[a]]
groupSorted = undefined
-- groupSorted [1,1,2,2,3,3] ==> [[1,1],[2,2],[3,3]]
How are we supposed to implement groupSorted? Well, I dunno. Let's think about that later. Pretend that we've implemented it. How would we use it to get the correct solution? I'm assuming it is OK to choose just one correct solution, in the event that there is more than one (as in your second example).
mode :: [a] -> a
mode xs = doSomething (groupSorted xs)
where doSomething :: [[a]] -> a
doSomething = undefined
-- doSomething [[1],[2],[3,3]] ==> 3
-- mode [1,2,3,3] ==> 3
We need to do something after we use groupSorted on the list. But what? Well...we should find the longest list in the list of lists. Right? That would tell us which element appears the most in the original list. Then, once we find the longest sublist, we want to return the element inside it.
chooseLongest :: [[a]] -> a
chooseLongest xs = head $ chooseBy (\ys -> length ys) xs
where chooseBy :: ([a] -> b) -> [[a]] -> a
chooseBy f zs = undefined
-- chooseBy length [[1],[2],[3,3]] ==> [3,3]
-- chooseLongest [[1],[2],[3,3]] ==> 3
chooseLongest is the doSomething from before. The idea is that we want to choose the best list in the list of lists xs, and then take one of its elements (its head does just fine). I defined this by creating a more general function, chooseBy, which uses a function (in this case, we use the length function) to determine which choice is best.
Now we're at the "hard" part. Folds. chooseBy and groupSorted are both folds. I'll step you through groupSorted, and leave chooseBy up to you.
How to write your own folds
We know groupSorted is a fold, because it consumes the entire list, and produces something entirely new.
groupSorted :: [Int] -> [[Int]]
groupSorted xs = foldr step start xs
where step :: Int -> [[Int]] -> [[Int]]
step = undefined
start :: [[Int]]
start = undefined
We need to choose an initial value, start, and a stepping function step. We know their types because the type of foldr is (a -> b -> b) -> b -> [a] -> b, and in this case, a is Int (because xs is [Int], which lines up with [a]), and the b we want to end up with is [[Int]].
Now remember, the stepping function will inspect the elements of the list, one by one, and use step to fuse them into an accumulator. I will call the currently inspected element v, and the accumulator acc.
step v acc = undefined
Remember, in theory, foldr works its way from right to left. So suppose we have the list [1,2,3,3]. Let's step through the algorithm, starting with the rightmost 3 and working our way left.
step 3 start = [[3]]
Whatever start is, when we combine it with 3 it should end up as [[3]]. We know this because if the original input list to groupSorted were simply [3], then we would want [[3]] as a result. However, it isn't just [3]. Let's pretend now that it's just [3,3]. [[3]] is the new accumulator, and the result we would want is [[3,3]].
step 3 [[3]] = [[3,3]]
What should we do with these inputs? Well, we should tack the 3 onto that inner list. But what about the next step?
step 2 [[3,3]] = [[2],[3,3]]
In this case, we should create a new list with 2 in it.
step 1 [[2],[3,3]] = [[1],[2],[3,3]]
Just like last time, in this case we should create a new list with 1 inside of it.
At this point we have traversed the entire input list, and have our final result. So how do we define step? There appear to be two cases, depending on a comparison between v and acc.
step v acc#((x:xs):xss) | v == x = (v:x:xs) : xss
| otherwise = [v] : acc
In one case, v is the same as the head of the first sublist in acc. In that case we prepend v to that same sublist. But if such is not the case, then we put v in its own list and prepend that to acc. So what should start be? Well, it needs special treatment; let's just use [] and add a special pattern match for it.
step elem [] = [[elem]]
start = []
And there you have it. All you have to do to write your on fold is determine what start and step are, and you're done. With some cleanup and eta reduction:
groupSorted = foldr step []
where step v [] = [[v]]
step v acc#((x:xs):xss)
| v == x = (v:x:xs) : xss
| otherwise = [v] : acc
This may not be the most efficient solution, but it works, and if you later need to optimize, you at least have an idea of how this function works.
I don't want to spoil all the fun, but a group function would be helpful. Unfortunately it is defined in Data.List, so you need to write your own. One possible way would be:
-- corrected version, see comments
grp [] = []
grp (x:xs) = let a = takeWhile (==x) xs
b = dropWhile (==x) xs
in (x : a) : grp b
E.g. grp [1,1,2,2,3,3,3] gives [[1,1],[2,2],[3,3,3]]. I think from there you can find the solution yourself.
I'd try the following:
mostFrequent = snd . foldl1 max . map mark . group
where
mark (a:as) = (1 + length as, a)
mark [] = error "cannot happen" -- because made by group
Note that it works for any finite list that contains orderable elements, not just integers.
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
Define a function replicate which given a list of numbers returns a
list with each number duplicated its value. Use a fold, map, and take
..> replicate [5,1,3,2,8,1,2]
output: [5,5,5,5,5,1,3,3,3,2,2,8,8,8,8,8,8,8,8,1,2,2]
I've figure this out using List comprehension and recursion:
replicate2 [] = []
replicate2 (n:nn) = take n(repeat n) ++ replicate2 nn
but how would you use fold and map to do this?
so far I have: replicate n = map (foldl1 (take n(repeat n)) n) n
which is obviously wrong, but I think I am close..
so any help would be nice, THANKS!
The key in Haskell is always follow the types:
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr1 :: (a -> a -> a) -> [a] -> a
map :: (a -> b) -> [a] -> [b]
take :: Int -> [a] -> [a]
I've added some spaces here to make it a bit more clear how these three functions compare. Remember when you look at these that a type variable, a or b, can match any type, including things like String, or [Float], or even [(String,[Int])]. For example, in the expression:
foldr (\a b -> product a + b) (0::Int) [[1,2,4],[5,2],[0,3,6]]
foldr is being used as type ([Int] -> Int -> Int) -> Int -> [[Int]] -> Int. That is a has matched [Int] and b has matched Int.
Now: Think about at the "outermost" level what your expression has to do. Which of these functions fits that form?
Can you cast your problem into an outer expression that has one of these forms and an "inner" problem?
You've got your function application order mixed up.
Think about what you need to be able to do:
Turn a number n into a list of n copies of itself
Apply operation #1 on every number in a list
Concatenate all the lists you got from #2 together.
You know how to do 1: take n $ repeat n
Of 2 and 3, which is a map and which is a fold?
Step 2. is a map - you're mapping ("transforming") every item in the list, into a list.
Step 3. is a fold, since you're aggregating ("flattening") a bunch of list elements into one.
replicate xs = foldl (++) [] (map (\n->take n $ repeat n) xs)
The idea is map on every element of a list which just repeats an element x , x number of times. Then fold on the list to concatenate it. Suppose the list is [5,1,2]
So (map (\n->take n $ repeat n) xs) is [[5,5,5,5,5],[1],[2,2]]
and then you just have to concatenate the inner lists.
replicate2 lst = concatMap(\x -> (take x) (repeat x)) lst