Basically, I want to create a function that takes a list of integers and another list (this list can be of any type) and produce another list that has the elements in it from the "other list" at intervals specified by the list of integers. If I input:
ixs [2,3,1] [3,2,1]
[2,1,3]
So far I have:
ix :: Int -> [a] -> a
ix a [] = error "Empty list"
ix 1 (x:xs) = x
ix a (x:xs) = ix (a-1) xs
ixs :: [Int] -> [a] -> [a]
ixs [] _ = []
ixs _ [] = []
ixs (x:xs) (y) = ix x y: []
With this code I only get one value returned like so:
ixs [1,2] [2,1]
[2]
How can I call the ix function repeatedly on (x:xs) so that it returns all the values I want?
Edit: I want to do this without using any standard prelude functions. I just want to use recursion.
This is (almost) a map of an indexing ("getting the value at") of the first list over the second list
import Data.List ((!!))
-- (!!) :: [a] -> Int -> a
ixs :: [Int] -> [b] -> [b]
ixs ary ixes = map (ary !!) ixes
But you also have wraparound when you index a 3-element list by (3 mod 3 = 0), so we ought to just map mod over the indexes
ixs ary ixes = map (ary !!) (map (`mod` length ary) ixes)
And then we can simplify to "pointless style"
ixs ary = map (ary !!) . map (`mod` length ary)
which reads nicely as "map the indices modulo the array length then map the array indexing over the resultant indices". And it gives the right result
> ixs [2,3,1] [3,2,1]
[2,1,3]
To break down the Prelude function and Data.List function, we have
(!!) :: [b] -> Int -> b
(x:_) !! 0 = x
(_:xs) !! n
| n > 0 = xs !! (n-1)
| otherwise = error "List.(!!): negative argument."
_ !! _ = error "List.(!!): index too large."
and
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs
You could reverse the order of the arguments
ix' :: [a] -> Int -> a
ix' [] a = error "Empty list"
ix' (x:xs) 1 = x
ix' (x:xs) a = ix' xs (a-1)
to make it easier to map ix over a list of indeces:
ixs' :: [a] -> [Int] -> [a]
ixs' xs is = map (ix' xs) is
Like this:
> ixs' "Hello Mum" [1,5,6,1,5,6,1,5]
"Ho Ho Ho"
but it would be nicer to use flip to swap the arguments - ix' is just flip ix, so you could do
ixs :: [Int] -> [a] -> [a]
ixs is xs = map (flip ix xs) is
which you then call the way round you'd planned:
> ixs [1,5,6,1,5,6,1,5] "Hello Mum"
"Ho Ho Ho"
Perhaps something like this
ixs :: [Int] -> [a] -> [a]
ixs idx a = map (`ix` a) idx
What you want to do is map your index function across all the values in the list of
indices to index the second list. Note that your ix function is just !! function, but starts indexing from 1 instead of 0.
Related
I have to replace all elements in a list by the number of occurrences of that element, like if I have "Taylor Swift" the result will be [1,1,1,1,1,1,1,1,1,1,1,1].
I already made the code to count the occurrences, I just know how to replace all elements by the number of they occurrence I already try:
ocurr :: [Char] -> Char -> Int
ocurr xs x = length(filter (x==) xs)
frequencias :: [Char] -> [Char]
frequencias "" = []
frequencias xs = [ ocurr xs y| y <- xs]
and
ocurr :: [Char] -> Char -> Int
ocurr xs x = length(filter (x==) xs)
frequencias :: [Char] -> [Char]
frequencias "" = []
frequencias xs = [x | y <- xs x = ocurr xs x]
but none of this works...
can anyone help me please?
This will not work since the return type you specify in frequencias is [Char], whereas the frequencies are, according to your occurr function, Ints. The special clause for an empty list is not necesary (although not wrong). You thus can work with:
frequencias :: [Char] -> [Int]
frequencias xs = [ ocurr xs y | y <- xs ]
you can also make use of a simple map :: (a -> b) -> [a] -> [b]:
frequencias :: [Char] -> [Int]
frequencias xs = map (ocurr xs) xs
This thus gives us:
Prelude> frequencias "Taylor Swift"
[1,1,1,1,1,1,1,1,1,1,1,1]
Prelude> frequencias "taylor swift"
[2,1,1,1,1,1,1,1,1,1,1,2]
All this filtering could get expensive. Here's an easy fix:
import qualified Data.IntMap.Strict as M
import Data.IntMap.Strict (IntMap)
import Data.Char (ord)
import Control.DeepSeq (force)
import Data.List (foldl')
frequencias :: [Char] -> [Int]
frequencias xs = force res
where
freq_map :: IntMap Int
freq_map = foldl' go M.empty xs
go fm c = M.insertWith (+) (ord c) 1 fm
res = map (\c -> case M.lookup (ord c) freq_map of
Just freq -> freq
Nothing -> error "impossible") xs
The force ensures that the frequency map will be garbage collected promptly; it's not necessary or probably desirable if the result is consumed promptly.
An alternative way to prevent a memory leak is to delete keys that are no longer needed:
import qualified Data.IntMap.Strict as M
import Data.IntMap.Strict (IntMap)
import Data.Char (ord)
import Data.List (foldl')
data Blob = Blob
{ total_count :: !Int
, remaining :: !Int
}
frequencias :: [Char] -> [Int]
frequencias xs0 = finish xs0 freq_map0
where
freq_map0 :: IntMap Blob
freq_map0 = foldl' go M.empty xs0
go fm c = M.alter f (ord c) fm
where
f Nothing = Just (Blob 1 1)
f (Just (Blob x _)) = Just (Blob (x + 1) (x + 1))
finish [] _ = []
finish (c : cs) freq_map = case M.updateLookupWithKey (\_ (Blob tot remn) ->
if remn == 1
then Nothing
else Just (Blob tot (remn - 1))) (ord c) freq_map of
(Nothing, _) -> error "Whoopsy"
(Just (Blob tot _), freq_map') -> tot : finish cs freq_map'
For comparison to #dfeuer's answer, here's a couple of lower-tech approaches.
Brute force approach. This has O(n^2) time complexity, for input list length n.
occurrences :: Eq a => [a] -> [Int]
occurrences xss = map (\ x -> count (== x) xss) xss
count :: (a -> Bool) -> [a] -> Int
count _ [] = 0
count p (x : xs) | p x = 1 + count p xs
| otherwise = count p xs
(I used English names for my functions ;-) count does the job of O.P.'s ocurr. But I've switched round the order of args to look more like Prelude.filter. ocurr is a little inefficient because filter builds an intermediate result to be the argument to length. We don't need to build that: merely count how many elements meet the predicate (== x).
(I'm quite surprised there isn't already a Prelude.count nor Data.List.count.)
This is inefficient because it traverses the list for every element, even if it already 'knows' the count for that element value -- i.e. because it's already met that element earlier in the list.
OTOH, if a large proportion of the elements occur only once, it avoids the overhead of building some sort of lookup structure.
Here's a version using an intermediate cache -- but only for elements known to occur more than once. Anybody like to guess what is its time complexity?
data Cache3 a = TheList3 [a] | Cached3 a Int (Cache3 a)
count3 :: (a -> Bool) -> Cache3 a -> (Int, Bool)
-- return both the count and whether it was cached
count3 p (TheList3 xss) = ( count p xss, False) -- reuse count from sol'n 1
count3 p (Cached3 x c xs) | p x = (c, True)
| otherwise = count3 p xs
-- don't cache if count = 1: we've just counted its only appearance so won't need it again
occurrences3 :: Eq a => [a] -> [Int]
occurrences3 xss = go (TheList3 xss) xss where
go _ [] = []
go cc (x: xs) = c: go (if cached || c < 2 then cc else ( Cached3 x c cc)) xs where
(c, cached) = count3 (== x) cc
I'm trying to change a list in haskell to include 0 between every element. If we have initial list [1..20] then i would like to change it to [1,0,2,0,3..20]
What i thought about doing is actually using map on every function, extracting element then adding it to list and use ++[0] to it but not sure if this is the right approach or not. Still learning haskell so might have errors.
My code:
x = map classify[1..20]
classify :: Int -> Int
addingFunction 0 [Int]
addingFunction :: Int -> [a] -> [a]
addingFunction x xs = [a] ++ x ++ xs
intersperse is made for this. Just import Data.List (intersperse), then intersperse 0 yourList.
You cannot do this with map. One of the fundamental properties of map is that its output will always have exactly as many items as its input, because each output element corresponds to one input, and vice versa.
There is a related tool with the necessary power, though:
concatMap :: (a -> [b]) -> [a] -> [b]
This way, each input item can produce zero or more output items. You can use this to build the function you wanted:
between :: a -> [a] -> [a]
sep `between` xs = drop 1 . concatMap insert $ xs
where insert x = [sep, x]
0 `between` [1..10]
[1,0,2,0,3,0,4,0,5,0,6,0,7,0,8,0,9,0,10]
Or a more concise definition of between:
between sep = drop 1 . concatMap ((sep :) . pure)
With simple pattern matching it should be:
addingFunction n [] = []
addingFunction n [x] = [x]
addingFunction n (x:xs) = x: n : (addingFunction n xs)
addingFunction 0 [1..20]
=> [1,0,2,0,3,0,4,0,5,0,6,0,7,0,8,0,9,0,10,0,11,0,12,0,13,0,14,0,15,0,16,0,17,0,18,0,19,0,20]
If you want to use map to solve this, you can do something like this:
Have a function that get a int and return 2 element list with int and zero:
addZero :: List
addZero a = [0, a]
Then you can call map with this function:
x = map addZero [1..20] -- this will return [[0,1], [0, 2] ...]
You will notice that it is a nested list. That is just how map work. We need a way to combine the inner list together into just one list. This case we use foldl
combineList :: [[Int]] -> [Int]
combineList list = foldl' (++) [] list
-- [] ++ [0, 1] ++ [0, 2] ...
So the way foldl work in this case is that it accepts a combine function, initial value, and the list to combine.
Since we don't need the first 0 we can drop it:
dropFirst :: [Int] -> [Int]
dropFirst list = case list of
x:xs -> xs
[] -> []
Final code:
x = dropFirst $ combineList $ map addZero [1..20]
addZero :: Int -> [Int]
addZero a = [0, a]
combineList :: [[Int]] -> [Int]
combineList list = foldl (++) [] list
dropFirst :: [Int] -> [Int]
dropFirst list = case list of
x:xs -> xs
[] -> []
We here can make use of a foldr pattern where for each element in the original list, we prepend it with an 0:
addZeros :: Num a => [a] -> [a]
addZeros [] = []
addZeros (x:xs) = x : foldr (((0 :) .) . (:)) [] xs
If you don't want to use intersperse, you can write your own.
intersperse :: a -> [a] -> [a]
intersperse p as = drop 1 [x | a <- as, x <- [p, a]]
If you like, you can use Applicative operations:
import Control.Applicative
intersperse :: a -> [a] -> [a]
intersperse p as = drop 1 $ as <**> [const p, id]
This is basically the definition used in Data.Sequence.
replicatee :: [a] -> Int -> [a]
replicatee [] _ = []
replicatee xs 0 = []
replicatee (x:xs) n = x:replicatee (x:xs) (n-1): replicatee xs n
So this is my code for replicating a an element in a list n times, the compler keeps showing an error :
Couldnt match type 'a'with [a], I'm seriously confused, please help out.
Edit : what i want my function to do is this:
replicatee [1,2,3,4] 2
[1,1,2,2,3,3,4,4]
I might have misunderstood your intention, but maybe you meant something like this:
replicatee :: a -> Int -> [a]
replicatee _ 0 = []
replicatee x n = x:replicatee x (n-1)
replicatee :: [a] -> Int -> [a]
replicatee [] _ = []
replicatee xs 0 = []
replicatee (x:xs) n = x:replicatee (x:xs) (n-1): replicatee xs n
The problem is that replicatee returns a value of type [a], but you try to add that to another list of type [a] using (:) :: a -> [a] -> [a]. From a type-checking perspective, you need to use (++), not (:):
replicatee xs'#(x:xs) n = x : (replicatee xs' (n-1) ++ replicatee xs n)
Whether it does what you intended is another matter. Based on your description, Mikkel provides the right answer.
I'm trying to write a function that deletes the second occurrence of an element in a list.
Currently, I've written a function that removes the first element:
removeFirst _ [] = []
removeFirst a (x:xs) | a == x = xs
| otherwise = x : removeFirst a xs
as a starting point. However,I'm not sure this function can be accomplished with list comprehension. Is there a way to implement this using map?
EDIT: Now I have added a removeSecond function which calls the first
deleteSecond :: Eq a => a -> [a] -> [a]
deleteSecond _ [] = []
deleteSecond a (x:xs) | x==a = removeFirst a xs
| otherwise = x:removeSecond a xs
However now the list that is returned removes the first AND second occurrence of an element.
Well, assuming you've got removeFirst - how about searching for the first occurence, and then using removeFirst on the remaining list?
removeSecond :: Eq a => a -> [a] -> [a]
removeSecond _ [] = []
removeSecond a (x:xs) | x==a = x:removeFirst a xs
| otherwise = x:removeSecond a xs
You could also implement this as a fold.
removeNth :: Eq a => Int -> a -> [a] -> [a]
removeNth n a = concatMap snd . scanl go (0,[])
where go (m,_) b | a /= b = (m, [b])
| n /= m = (m+1, [b])
| otherwise = (m+1, [])
and in action:
λ removeNth 0 1 [1,2,3,1]
[2,3,1]
λ removeNth 1 1 [1,2,3,1]
[1,2,3]
I used scanl rather than foldl or foldr so it could both pass state left-to-right and work on infinite lists:
λ take 11 . removeNth 3 'a' $ cycle "abc"
"abcabcabcbc"
Here is an instinctive implementation using functions provided by List:
import List (elemIndices);
removeSecond x xs = case elemIndices x xs of
(_:i:_) -> (take i xs) ++ (drop (i+1) xs)
_ -> xs
removeNth n x xs = let indies = elemIndices x xs
in if length indies < n
then xs
else let idx = indies !! (n-1)
in (take idx xs) ++ (drop (idx+1) xs)
Note: This one cannot handle infinite list, and its performance may not be good for very large list.
Please help me writing a function which takes two arguments: a list of ints and an index (int) and returns a list of integers with negative values on specified index position in the table.
The function would have this signatureMyReverse :: [Int]->Int->[Int].
For example: myReverse [1,2,3,4,5] 3 = [1,2,-3,4,5].
If the index is bigger than the length of the list or smaller than 0, return the same list.
myReverse :: [Int] -> Int -> [Int]
myReverse [] n = []
myReverse (x:xs) n
| n < 0 = x:xs
| n == 0 = (-x):xs
| otherwise = x:(myReverse xs (n-1))
That's indexing the array from 0; your example indexes from 1, but is undefined for the case n == 0. The fix to take it to index from 1 should be fairly obvious :)
Also, your capitalisation is inconsistent; MyReverse is different to myReverse, and only the latter is valid as a function.
Results, in GHCi:
*Main> myReverse [10,20,30,40,50] 0
[-10,20,30,40,50]
*Main> myReverse [10,20,30,40,50] 2
[10,20,-30,40,50]
*Main> myReverse [10,20,30,40,50] 3
[10,20,30,-40,50]
*Main> myReverse [10,20,30,40,50] 5
[10,20,30,40,50]
*Main> myReverse [10,20,30,40,50] (-1)
[10,20,30,40,50]
More generic version that does the same thing, using a pointless definition for myReverse:
myGeneric :: (a -> a) -> [a] -> Int -> [a]
myGeneric f [] n = []
myGeneric f (x:xs) n
| n < 0 = x:xs
| n == 0 = (f x):xs
| otherwise = x:(myGeneric f xs (n-1))
myReverse :: [Int] -> Int -> [Int]
myReverse = myGeneric negate
myReverse :: [Int] -> Int -> [Int]
myReverse [] _ = []
myReverse list n
|length list < n = list
myReverse (x:xs) n
|n == 0 = -x : myReverse xs (n-1)
|otherwise = x : myReverse xs (n-1)
myReverse :: [Int] -> Int -> [Int]
myReverse [] _ = []
myReverse list n
|length list < n = list
myReverse (x:xs) n
|n == 0 = -x : myReverse xs (n-1)
|otherwise = x : myReverse xs (n-1)