I am having some issues writing a Haskell function. I am trying to get the average of a list of triples of doubles. when I divide by just the ' length xs ' , I get an error that the length is an Int, so I tried using fromIntegeral and its not giving me an error but not giving the right answer. For example if I test,
averages [(2.0,1.0,3.0)] it returns [6.0]
averages :: [(Double, Double, Double)] -> [Double]
averages xs = [ (x+y+z) / fromIntegral (length xs) | (x,y,z) <- xs ]
You are missunderstanding your own type function, the avarage is always over 3, because you have a list of triplets (or tuples of three?):
averages :: [(Double, Double, Double)] -> [Double]
averages xs = [ (x+y+z) / 3 | (x,y,z) <- xs ]
$> averages [(8,6,7), (4,4,10), (1,1,1)]
=> [7.0,6.0,1.0]
Note that length xs will evaluate to 1 when you evaluate averages [(2.0,1.0,3.0)]. The list contains a single element: a tuple. Since you are averaging the elements of a triplet, you can just divide by 3.
Others have explained why you're getting the wrong answers, but I would like to urge you to break up your problem into two pieces.
averageTriple :: (Double, Double, Double) -> Double
averageTriple (x,y,z) = ...
averageTriples :: [(Double, Double, Double)] -> [Double]
averageTriples ts = ... -- use averageTriple here
Related
I am running into a wall when I'm trying to calculate % growth from a list of integers to a list of floats. I am new to Haskell with very little experience and not sure where or what to search for my problem thus I came here. :)
function :: [Ints] -> [Floats]
I have a list.
nums = [4561,3241,2345,3455,4567]
I need to iterate through the list and calculate the % percentage growth from nums[4] to nums[0]
and then output a list of floats. But I am not sure whether to use a map function or some other method to solve this. I need some way to retrieve two numbers from the list i.e. nums[4] and nums[3] and calculate the % growth.
I'm not sure what you need but if it's the growth from (n-1)th to the nth element you can do it like this:
growth :: [Int] -> [Float]
growths xs =
zipWith (\n n' -> fromIntegral (n'-n) / fromIntegral n * 100) xs (tail xs)
yielding
> growths [4561,3241,2345,3455,4567]
[-28.941021,-27.645788,47.334755,32.185238]
-- this one makes it a bit more obvious what is happening
> growths [1,2,3,4,5]
[100.0,50.0,33.333336,25.0]
I probably got the formula wrong and you want some other formula but the idea should be clear as long as you want to compare consecutive numbers.
The trick zipWith f xs (tail xs) is often useful to work with consecutive elements in a list. Here the first argument to f is the (n-1)th and the second is the nth element in the list.
if you need from n to n-1th (as you kind of seem to imply) just flip the arguments:
growths xs =
zipWith (\n' n -> fromIntegral (n'-n) / fromIntegral n * 100) xs (tail xs)
> growths [4561,3241,2345,3455,4567]
[40.72817,38.208954,-32.12735,-24.348589]
> growths [1,2,3,4,5]
[-50.0,-33.333336,-25.0,-20.0]
I'm interested in writing an efficient Haskell function triangularize :: [a] -> [[a]] that takes a (perhaps infinite) list and "triangularizes" it into a list of lists. For example, triangularize [1..19] should return
[[1, 3, 6, 10, 15]
,[2, 5, 9, 14]
,[4, 8, 13, 19]
,[7, 12, 18]
,[11, 17]
,[16]]
By efficient, I mean that I want it to run in O(n) time where n is the length of the list.
Note that this is quite easy to do in a language like Python, because appending to the end of a list (array) is a constant time operation. A very imperative Python function which accomplishes this is:
def triangularize(elements):
row_index = 0
column_index = 0
diagonal_array = []
for a in elements:
if row_index == len(diagonal_array):
diagonal_array.append([a])
else:
diagonal_array[row_index].append(a)
if row_index == 0:
(row_index, column_index) = (column_index + 1, 0)
else:
row_index -= 1
column_index += 1
return diagonal_array
This came up because I have been using Haskell to write some "tabl" sequences in the On-Line Encyclopedia of Integer Sequences (OEIS), and I want to be able to transform an ordinary (1-dimensional) sequence into a (2-dimensional) sequence of sequences in exactly this way.
Perhaps there's some clever (or not-so-clever) way to foldr over the input list, but I haven't been able to sort it out.
Make increasing size chunks:
chunks :: [a] -> [[a]]
chunks = go 0 where
go n [] = []
go n as = b : go (n+1) e where (b,e) = splitAt n as
Then just transpose twice:
diagonalize :: [a] -> [[a]]
diagonalize = transpose . transpose . chunks
Try it in ghci:
> diagonalize [1..19]
[[1,3,6,10,15],[2,5,9,14],[4,8,13,19],[7,12,18],[11,17],[16]]
This appears to be directly related to the set theory argument proving that the set of integer pairs are in one-to-one correspondence with the set of integers (denumerable). The argument involves a so-called Cantor pairing function.
So, out of curiosity, let's see if we can get a diagonalize function that way.
Define the infinite list of Cantor pairs recursively in Haskell:
auxCantorPairList :: (Integer, Integer) -> [(Integer, Integer)]
auxCantorPairList (x,y) =
let nextPair = if (x > 0) then (x-1,y+1) else (x+y+1, 0)
in (x,y) : auxCantorPairList nextPair
cantorPairList :: [(Integer, Integer)]
cantorPairList = auxCantorPairList (0,0)
And try that inside ghci:
λ> take 15 cantorPairList
[(0,0),(1,0),(0,1),(2,0),(1,1),(0,2),(3,0),(2,1),(1,2),(0,3),(4,0),(3,1),(2,2),(1,3),(0,4)]
λ>
We can number the pairs, and for example extract the numbers for those pairs which have a zero x coordinate:
λ>
λ> xs = [1..]
λ> take 5 $ map fst $ filter (\(n,(x,y)) -> (x==0)) $ zip xs cantorPairList
[1,3,6,10,15]
λ>
We recognize this is the top row from the OP's result in the text of the question.
Similarly for the next two rows:
λ>
λ> makeRow xs row = map fst $ filter (\(n,(x,y)) -> (x==row)) $ zip xs cantorPairList
λ> take 5 $ makeRow xs 1
[2,5,9,14,20]
λ>
λ> take 5 $ makeRow xs 2
[4,8,13,19,26]
λ>
From there, we can write our first draft of a diagonalize function:
λ>
λ> printAsLines xs = mapM_ (putStrLn . show) xs
λ> diagonalize xs = takeWhile (not . null) $ map (makeRow xs) [0..]
λ>
λ> printAsLines $ diagonalize [1..19]
[1,3,6,10,15]
[2,5,9,14]
[4,8,13,19]
[7,12,18]
[11,17]
[16]
λ>
EDIT: performance update
For a list of 1 million items, the runtime is 18 sec, and 145 seconds for 4 millions items. As mentioned by Redu, this seems like O(n√n) complexity.
Distributing the pairs among the various target sublists is inefficient, as most filter operations fail.
To improve performance, we can use a Data.Map structure for the target sublists.
{-# LANGUAGE ExplicitForAll #-}
{-# LANGUAGE ScopedTypeVariables #-}
import qualified Data.List as L
import qualified Data.Map as M
type MIL a = M.Map Integer [a]
buildCantorMap :: forall a. [a] -> MIL a
buildCantorMap xs =
let ts = zip xs cantorPairList -- triplets (a,(x,y))
m0 = (M.fromList [])::MIL a
redOp m (n,(x,y)) = let afn as = case as of
Nothing -> Just [n]
Just jas -> Just (n:jas)
in M.alter afn x m
m1r = L.foldl' redOp m0 ts
in
fmap reverse m1r
diagonalize :: [a] -> [[a]]
diagonalize xs = let cm = buildCantorMap xs
in map snd $ M.toAscList cm
With that second version, performance appears to be much better: 568 msec for the 1 million items list, 2669 msec for the 4 millions item list. So it is close to the O(n*Log(n)) complexity we could have hoped for.
It might be a good idea to craete a comb filter.
So what does comb filter do..? It's like splitAt but instead of splitting at a single index it sort of zips the given infinite list with the given comb to separate the items coressponding to True and False in the comb. Such that;
comb :: [Bool] -- yields [True,False,True,False,False,True,False,False,False,True...]
comb = iterate (False:) [True] >>= id
combWith :: [Bool] -> [a] -> ([a],[a])
combWith _ [] = ([],[])
combWith (c:cs) (x:xs) = let (f,s) = combWith cs xs
in if c then (x:f,s) else (f,x:s)
λ> combWith comb [1..19]
([1,3,6,10,15],[2,4,5,7,8,9,11,12,13,14,16,17,18,19])
Now all we need to do is to comb our infinite list and take the fst as the first row and carry on combing the snd with the same comb.
Lets do it;
diags :: [a] -> [[a]]
diags [] = []
diags xs = let (h,t) = combWith comb xs
in h : diags t
λ> diags [1..19]
[ [1,3,6,10,15]
, [2,5,9,14]
, [4,8,13,19]
, [7,12,18]
, [11,17]
, [16]
]
also seems to be lazy too :)
λ> take 5 . map (take 5) $ diags [1..]
[ [1,3,6,10,15]
, [2,5,9,14,20]
, [4,8,13,19,26]
, [7,12,18,25,33]
, [11,17,24,32,41]
]
I think the complexity could be like O(n√n) but i can not make sure. Any ideas..?
I'm new to Haskell and trying to write a simple function. I would like to get each element compressed by its upcoming frequency.
For example input: "aabbcca" and the result I would like to get is
[('a',2), ('b',2), ('c',2), ('a',1)]
My code now looks like this:
import Data.List
compress :: String -> [(Char, Int)]
compress n = [ (x,y) | x:xs <- group n, y <- ? ]
I'm stuck and don't really know how I should count the elements. Any advice?
There is no need here to use another generator in your list. You can calculate the length :: Foldable f => f a -> Int of the group xs here. We use here an as-pattern [zvon.org] to have both access to the entire group, and the first item of that group:
compress :: Eq a => [a] -> [(a, Int)]
compress n = [ (x, length xs) | xs#(x:_) <- group n ]
The next lines should show how its has to work..
[14,2,344,41,5,666] after [(14,2),(2,1),(344,3),(5,1),(666,3)]
["Zoo","School","Net"] after [("Zoo",3),("School",6),("Net",3)]
Thats my code up to now
zipWithLength :: [a] -> [(a, Int)]
zipWithLength (x:xs) = zipWith (\acc x -> (x, length x):acc) [] xs
I want to figure out what the problem in the second line is.
If you transform the numbers into strings (using show), you can apply length on them:
Prelude> let zipWithLength = map (\x -> (x, length (show x)))
Prelude> zipWithLength [14,2,344,41,5,666]
[(14,2),(2,1),(344,3),(41,2),(5,1),(666,3)]
However, you cannot use the same function on a list of strings:
Prelude> zipWithLength ["Zoo","School","Net"]
[("Zoo",5),("School",8),("Net",5)]
The numbers are not the lengths of the strings, but of their representations:
Prelude> show "Zoo"
"\"Zoo\""
Prelude> length (show "Zoo")
5
As noted in the comments, similar problems may happen with other types of elements:
Prelude> zipWithLength [(1.0,3),(2.5,3)]
[((1.0,3),7),((2.5,3),7)]
Prelude> show (1.0,3)
"(1.0,3)"
Prelude> length (show (1.0,3))
7
If you want to apply a function on every element of a list, that is a map :: (a -> b) -> [a] -> [b]. The map thus takes a function f and a list xs, and generates a list ys, such that the i-th element of ys, is f applied to the i-th element of xs.
So now the only question is what mapping function we want. We want to take an element x, and return a 2-tuple (x, length x), we can express this with a lambda expression:
mapwithlength = map (\x -> (x, length x))
Or we can use ap :: Monad m => m (a -> b) -> m a -> m b for that:
import Control.Monad(ap)
mapwithlength = map (ap (,) length)
A problem is that this does not work for Ints, since these have no length. We can use show here, but there is an extra problem with that: if we perform show on a String, we get a string literal (this means that we get a string that has quotation marks, and where some characters are escaped). Based on the question, we do not want that.
We can define a parameterized function for that like:
mapwithlength f = map (ap (,) (length . f))
We can basically leave it to the user. In case they want to work with integers, they have to call it with:
forintegers = mapwithlength show
and for Strings:
forstrings = mapwithlength id
After installing the number-length package, you can do:
module Test where
import Data.NumberLength
-- use e.g for list of String
withLength :: [[a]] -> [([a], Int)]
withLength = map (\x -> (x, length x))
-- use e.g for list of Int
withLength' :: NumberLength a => [a] -> [(a, Int)]
withLength' = map (\x -> (x, numberLength x))
Examples:
>>> withLength ["Zoo", "bear"]
[("Zoo",3),("bear",4)]
>>> withLength' [14, 344]
[(14,2),(344,3)]
As bli points out, calculating the length of a number using length (show n) does not transfer to calculating the length of a string, since show "foo" becomes "\"foo\"". Since it is not obvious what the length of something is, you could parameterise the zip function with a length function:
zipWithLength :: (a -> Int) -> [a] -> [(a, Int)]
zipWithLength len = map (\x -> (x, len x))
Examples of use:
> zipWithLength (length . show) [7,13,666]
[(7,1),(13,2),(666,3)]
> zipWithLength length ["Zoo", "School", "Bear"]
[("Zoo",3),("School",6),("Bear",4)]
> zipWithLength (length . concat) [[[1,2],[3],[4,5,6,7]], [[],[],[6],[6,6]]]
[([[1,2],[3,4],[5,6,7]],7),([[],[],[6],[6,6]],3)]
Trying to create a function which takes in two lists, the first being a list of characters, the second being positive integers. The function then repeats the characters in the first list the number of times the same position number in the second list is. Ex:
myCount ['a','b'] ['1','2'] => ['a','b','b']
What I have so far:
myCount :: [Char] -> [Int] -> [Char]
myCount [] [] = []
myCount (x:xs) (y:ys) = replicate y x && myCount xs ys
I am replicating the char from the first list (x) y times and then recursively doing this for the entire lists.
Any help or pointers in the right direction would be great!
My Error is:
mess.hs:10:43: error:
* Couldn't match expected type `Bool' with actual type `[Char]'
* In the second argument of `(&&)', namely `myCount xs ys'
In the expression: replicate y x && myCount xs ys
In an equation for `myCount':
myCount (x : xs) (y : ys) = replicate y x && myCount xs ys
How did you come up with the idea of using && for this? That's a logical and operator, i.e. it combines two truth-values (Bool) to a value that's True only if both sides are true.
What you're dealing with are not boolean values but lists, though. You want to combine two lists to a list that starts with the first and continues with the other. IOW, you want a function with type [Char] -> [Char] -> [Char]. Actually it shouldn't matter that the list elements are Chars, this should work for lists containing any types: [a] -> [a] -> [a]. Well, you can hoogle that! The first result is
(++) :: [a] -> [a] -> [a] infixr 5
Append two lists, i.e.,
[x1, ..., xm] ++ [y1, ..., yn] == [x1, ..., xm, y1, ..., yn]
[x1, ..., xm] ++ [y1, ...] == [x1, ..., xm, y1, ...]
If the first list is not finite, the result is the first list.
Sounds good, doesn't it? So, this is the function you're trying to write:
replicates :: [Int] -> [a] -> [a]
replicates (n:ns) (x:xs) = replicate n x ++ replicates ns xs
replicates _ _ = []
Alternatively, you can define this as
replicates ns = concat . zipWith replicate ns