I'm trying to count how many numbers in the input list are in the given low-high range.
Here's what I have so far:
countRange :: Int -> Int -> [Int] -> Int
countRange _ _ [] = 0
countRange low high (x:xs) | (low < x) && (high > x) = 1 + (countRange low high xs)
| otherwise = countRange low high xs
Some examples:
countRange 5 8 [] ==> 0
countRange 1 3 [1,2,3,4,5] ==> 3
I think this is more of a semantical discussion. Your code works fine if we assume that the ranges are exclusive. But your example suggest that the bounds are inclusive, so we can rewrite this to:
countRange :: Int -> Int -> [Int] -> Int
countRange _ _ [] = 0
countRange low high (x:xs) | low <= x && high >= x = 1 + countRange low high xs
| otherwise = countRange low high xs
But I think you make it too hard here. You can count the number of elements in a list with length, and we can filter the elements with filter, so we can write it in a compact way with:
countRange :: Int -> Int -> [Int] -> Int
countRange low hig = length . filter f
where f x = x >= low && x <= hig
Note that we can generalize the function signature without any additional effort:
countRange :: Ord a => a -> a -> [a] -> Int
countRange low hig = length . filter f
where f x = x >= low && x <= hig
Related
I am learning Haskell and am currently creating a program that finds all common divisors from 3 different Int:s.
I have a working program but the evaluation time is very long on big numbers. I want advice on how to optimize it.
EXAMPLE: combineDivisors 234944 246744 144456 == [1,2,4,8]
As said I am very new to this so any help is appreciated.
import Data.List
combineDivisors :: Int -> Int -> Int -> [Int]
combineDivisors n1 n2 n3 =
mergeSort list
where list = getTrips concList
concList = isDivisor n1 ++ isDivisor n2 ++ isDivisor n3
isDivisor n = [x | x <- [1..n], mod n x == 0]
getTriplets :: Ord a => [a] -> [a]
getTriplets = map head . filter (\l -> length l > 2) . group . sort
--Merge sort--
split :: [a] -> ([a],[a])
split xs =
let
l = length xs `div` 2
in
(take l xs, drop l xs)
merge :: [Int] -> [Int] -> [Int]
merge [] ys = ys
merge xs [] = xs
merge (x:xs) (y:ys)
| y < x = y : merge (x:xs) ys
| otherwise = x : merge xs (y:ys)
mergeSort :: [Int] -> [Int]
mergeSort [] = []
mergeSort [x] = [x]
mergeSort xs =
let
(xs1,xs2) = split xs
in
merge (mergeSort xs1) (mergeSort xs2)
If you don't care too much about memory usage, you can just use Data.IntSet and a function to find all factors given a number to do this.
First, let's make a function that returns an IntSet of all factors of a number-
import qualified Data.IntSet as IntSet
factors :: Int -> IntSet.IntSet
factors n = IntSet.fromList . f $ 1 -- Convert the list of factors into a set
where
-- Actual function that returns the list of factors
f :: Int -> [Int]
f i
-- Exit when i has surpassed square root of n
| i * i > n = []
| otherwise = if n `mod` i == 0
-- n is divisible by i - add i and n / i to the list
then i : n `div` i : f (i + 1)
-- n is not divisible by i - continue to the next
else f (i + 1)
Now, once you have the IntSet corresponding to each number, you just have to do a intersection on them to get the result
commonFactors :: Int -> Int -> Int -> [Int]
commonFactors n1 n2 n3 = IntSet.toList $ IntSet.intersection (factors n3) $ IntSet.intersection (factors n1) $ factors n2
That works but is a bit ugly. How about making an intersections function that can take multiple IntSets and produce a final intersection result.
intersections :: [IntSet.IntSet] -> IntSet.IntSet
intersections [] = IntSet.empty
intersections (t:ts) = foldl IntSet.intersection t ts
That should fold on a list of IntSets to find the final intersection
Now you can refactor commonFactors to-
commonFactors :: Int -> Int -> Int -> [Int]
commonFactors n1 n2 n3 = IntSet.toList . intersections $ [factors n1, factors n2, factors n3]
Better? I'd think so. How about one last improvement, a general commonFactors function for n amount of ints
commonFactors :: [Int] -> [Int]
commonFactors = IntSet.toList . intersections . map factors
Note that this is using an IntSet, so it is naturally limited to Ints. If you want to use Integer instead - just replace IntSet with a regular Set Integer
Output
> commonFactors [234944, 246744, 144456]
[1,2,4,8]
You should use the standard algorithm where you prime factorize their GCD:
import Data.List
import qualified Data.Map.Strict as M
-- infinite list of primes
primes :: [Integer]
primes = 2:3:filter
(\n -> not $ any
(\p -> n `mod` p == 0)
(takeWhile (\p -> p * p <= n) primes))
[5,7..]
-- prime factorizing a number
primeFactorize :: Integer -> [Integer]
primeFactorize n
| n <= 1 = []
-- we search up to the square root to find a prime factor
-- if we find one then add it to the list, divide and recurse
| Just p <- find
(\p -> n `mod` p == 0)
(takeWhile (\p -> p * p <= n) primes) = p:primeFactorize (n `div` p)
-- if we don't then the number has to be prime so we're done
| otherwise = [n]
-- count the number of each element in a list
-- e.g.
-- getCounts [1, 2, 2, 3, 4] == fromList [(1, 1), (2, 2), (3, 1), (4, 1)]
getCounts :: (Ord a) => [a] -> M.Map a Int
getCounts [] = M.empty
getCounts (x:xs) = M.insertWith (const (+1)) x 1 m
where m = getCounts xs
-- get all possible combinations from a map of counts
-- e.g. getCombos (M.fromList [('a', 2), ('b', 1), ('c', 2)])
-- == ["","c","cc","b","bc","bcc","a","ac","acc","ab","abc","abcc","aa","aac","aacc","aab","aabc","aabcc"]
getCombos :: M.Map a Int -> [[a]]
getCombos m = allFactors
where
list = M.toList m
factors = fst <$> list
counts = snd <$> list
possible = (\n -> [0..n]) <$> counts
allCounts = sequence possible
allFactors = (\count -> concat $ zipWith replicate count factors) <$> allCounts
-- get the common factors of a list of numbers
commonFactorsList :: [Integer] -> [Integer]
commonFactorsList [] = []
commonFactorsList l = sort factors
where
totalGcd = foldl1 gcd l
-- then get the combinations them and take their products to get the factor
factors = map product . getCombos . getCounts . primeFactorize $ totalGcd
-- helper function for 3 numbers
commonFactors3 :: Integer -> Integer -> Integer -> [Integer]
commonFactors3 a b c = commonFactorsList [a, b, c]
I am trying to set the range of the list by the values that I give. I was able to set the head of the list and write the rest of it. However I am couldn't make the list stop at the hi value that I put in the function. How do I make my list stop at that specific value?
I tried different combinations between the conditions that I wrote. I tried putting x > hi = [] as the first condition, I thought once the next element on the list was greater than hi the list would end.
inRangeRec :: Int -> Int -> [Int] -> [Int]
inRangeRec lo hi [] = []
inRangeRec lo hi (x:xs) | lo <= x && x <= hi = lo : [ x | x <- xs]
| otherwise = inRangeRec lo hi xs
| x > hi = []
I expect inRangeRec 3 5 [1..10] == [3,4,5]
but the output I get is [3,4,5,6,7,8,9,10]
I think what you are trying to say is to let the value x if it is in range, if not, remove it, and stop if x is greater than max, so:
inRangeRec :: Int -> Int -> [Int] -> [Int]
inRangeRec lo hi [] = []
inRangeRec lo hi xss#(x:xs) | lo <= x && x <= hi = x : inRangeRec lo hi xs
| x > hi = []
| otherwise = inRangeRec lo hi xs
We can make use of takeWhile :: (a -> Bool) -> [a] -> [a] to take elements as long as a certain condition holds.
We can here thus use filter and takeWhile, like:
inRange :: Ord a => a -> a -> [a] -> [a]
inRange lo hi = filter (> lo) . takeWhile (< hi)
or in case we know that the list is in ascending order, we can use dropWhile :: (a -> Bool) -> [a] -> [a] as well:
inRange :: Ord a => a -> a -> [a] -> [a]
inRange lo hi = dropWhile (< lo) . takeWhile (< hi)
I´m new to Haskell.
Let´s say I want to sum up the first n elements of a list with a generated function on my own. I don´t know how to do this with Haskell. I just know how to sum up a whole given list, e.g.
sumList :: [Int] -> Int
sumList [] = 0
sumList (x:xs) = x + sumList xs
In order to sum up the first n elements of a list, for example
take the first 5 numbers from [1..10], which is 1+2+3+4+5 = 15
I thought I could do something like this:
sumList :: Int -> [Int] -> Int
sumList take [] = 0
sumList take (x:xs) = x + take $ sumList xs
But it doesn´t work... What´s wrong?
So you know how to sum up the numbers in a list,
sumList :: [Int] -> Int
sumList [] = 0
sumList (x:xs) = x + sumList xs
and if that list has no more than 5 elements in it, this function will even return the correct result if you indeed intended to sum no more than 5 elements in an argument list. Let's make our expectations explicit by renaming this function,
sumUpToFiveElements :: [Int] -> Int
sumUpToFiveElements [] = 0
sumUpToFiveElements (x:xs) = x + sumUpToFiveElements xs
it won't return the correct result for lists longer than five, but at least the name is right.
Can we fix that? Can we count up to 5? Can we count up to 5 while also advancing along the input list as we do?
sumUpToFiveElements :: Int -> [Int] -> Int
sumUpToFiveElements counter [] = 0
sumUpToFiveElements counter (x:xs) = x + sumUpToFiveElements (counter + 1) xs
This still isn't right of course. We do now count, but for some reason we ignore the counter. What is the right time to react to the counter, if we want no more than 5 elements? Let's try counter == 5:
sumUpToFiveElements :: Int -> [Int] -> Int
sumUpToFiveElements 5 [] = 0
sumUpToFiveElements counter [] = 0
sumUpToFiveElements counter (x:xs) = x + sumUpToFiveElements (counter + 1) xs
But why do we demand the list to also be empty when 5 is reached? Let's not do that:
sumUpToFiveElements :: Int -> [Int] -> Int
sumUpToFiveElements 5 _ = 0 -- the wildcard `_` matches *anything*
sumUpToFiveElements counter [] = 0
sumUpToFiveElements counter (x:xs) = x + sumUpToFiveElements (counter + 1) xs
Success! We now stop counting when 5 is reached! More, we also stop the summation!!
Wait, but what was the initial value of counter? We didn't specify it, so it's easy for a user of our function (that would be ourselves) to err and use an incorrect initial value. And by the way, what is the correct initial value?
Okay, so let's do this:
sumUpToFiveElements :: [Int] -> Int
sumUpToFiveElements xs = go 1 xs -- is 1 the correct value here?
where
go counter _ | counter == 5 = 0
go counter [] = 0
go counter (x:xs) = x + go (counter + 1) xs
Now we don't have that extraneous argument that made our definition so brittle, so prone to a user error.
And now for the punchline:
Generalize! (by replacing an example value with a symbolic one; changing 5 to n).
sumUpToNElements :: Int -> [Int] -> Int
sumUpToNElements n xs = .......
........
Done.
One more word of advice: don't use $ while at the very beginning of your learning Haskell. Use explicit parens.
sumList take (x:xs) = x + take $ sumList xs
is parsed as
sumList take (x:xs) = (x + take) (sumList xs)
This adds together two unrelated numbers, and then uses the result as a function to be called with (sumList xs) as an argument (in other words it's an error).
You probably wouldn't write it that way if you were using explicit parens.
Well you should limit the number of values with a parameter (preferably not take, since
that is a function from the Prelude), and thus limit the numbers.
This limiting in your code is apparently take $ sumList xs which is very strange: in your function take is an Int, and $ will basically write your statement to (x + take) (sumList xs). You thus apparently want to perform a function application with (x + take) (an Int) as function, and sumList xs as argument. But an Int is not a function, so it does not typecheck, nor does it include any logic to limit the numbers.
So basically we should consider three cases:
the empty list in which case the sum is 0;
the number of elements to take is less than or equal to zero, in that case the sum is 0; and
the number of elements to take is greater than 0, in that case we add the head to the sum of taking one element less from the tail.
So a straightforward mapping is:
sumTakeList :: (Integral i, Num n) => i -> [n] -> n
sumTakeList _ [] = 0
sumTakeList t (x:xs) | t <= 0 = 0
| otherwise = x + sumTakeList (t-1) xs
But you do not need to write such logic yourself, you can combine the take :: Int -> [a] -> [a] builtin with the sum :: Num a => [a] -> a functions:
sumTakeList :: Num n => Int -> [n] -> n
sumTakeList t = sum . take t
Now if you need to sum the first five elements, we can make that a special case:
subList5 :: Num n => [n] -> n
sumList5 = sumTakeList 5
A great resource to see what functions are available and how they work is Hoogle. Here is its page on take and the documentation for the function you want.
As you can see, the name take is taken, but it is a function you can use to implement this.
Note that your sumList needs another argument, the number of elements to sum. the syntax you want is something like:
sumList :: Int -> [Int] -> Int
sumList n xs = _ $ take n xs
Where the _ are blanks you can fill in yourself. It's a function in the Prelude, but the type signature is a little too complicated to get into right now.
Or you could write it recursively, with two base cases and a third accumulating parameter (by means of a helper function):
sumList :: Int -> [Int] -> Int
sumList n xs = sumList' n xs 0 where
sumList' :: Int -> [Int] -> Int -> Int
sumList' 0 _ a = _ -- A base case.
sumList' _ [] a = _ -- The other base case.
sumList' m (y:ys) a = sumList' _ _ _ -- The recursive case.
Here, the _ symbols on the left of the equals signs should stay there, and mean that the pattern guard ignores that parameter, but the _ symbols on the right are blanks for you to fill in yourself. Again, GHC will tell you the type you need to fill the holes with.
This kind of tail-recursive function is a very common pattern in Haskell; you want to make sure that each recursive call brings you one step closer to the base case. Often, that will mean calling itself with 1 subtracted from a count parameter, or calling itself with the tail of the list parameter as the new list parameter. here, you want to do both. Don't forget to update your running sum, a, when you have the function call itself recursively.
Here's a short-but-sweet answer. You're really close. Consider the following:
The take parameter tells you how many elements you need to sum up, so if you do sumList 0 anything you should always get 0 since you take no elements.
If you want the first n elements, you add the first element to your total and compute the sum of the next n-1 elements.
sumList 0 anything = 0
sumList n [] = 0
sumList n (e:es) = e + sumList (n-1) e
I got a problem with this exercise. I've been trying to solve it for a long time searching for stuff, but I am unable to.
Define functions:
addLnat :: [Int] -> [Int] -> [Int]
mulLnat :: [Int] -> [Int] -> [Int]
addLnat adds numbers from two arrays eg.
addLnat [4,5,6] [8,5,2] -> [2,1,9]
as [4+8 gives 2 carry 1, 5+5+1 gives 1 carry 1, 6+2+1 = 9]
Lnat, is a "list natural number", represented as a list of base-10 digits, least significant first. So the number 654 is [4,5,6].
What I got is:
addLnat :: [Int] -> [Int] -> [Int]
addLnat _ [] = []
addLnat [] _ = []
addLnat (x:xs) (y:ys) = (if (x+y) > 9 then x+y-10 else (x+y)):(addLnat xs ys)
I adding number and ignoring carry. Not sure how to solve it.
Any help would be much appreciated.
I have improved the solution as per user5402 comment, so created addLnat' cr xs ys, but when I what to pass carry as a parameter it fails to load - most probable that I am getting the syntax wrong:(
(cr is 0 only for now and it will be replaced by maths).
addLnat' c (x:xs) (y:ys) = d : addLnat' cr xs ys
where d = if c+x+y < 9 then x+y else c+x+y-((quot (c+x+y) 10)*10)
cr = 0
Any ideas?
I am not very good at haskell but maybe this can help ;
add::[Int]->[Int]->[Int]
add x y = add' 0 x y
There we define a function add that will use add' to add two lists The main idea is to "save" carry and carefully work with corner cases. Here carry is saved in "variable" rest
add'::Int->[Int]->[Int]->[Int]
add' 0 x [] = x
add' rest (x:[]) (y:[]) = [(r `mod` 10),(r `div` 10)]
where r = x+y+rest
add' y (x:xs) [] = add' (r `div` 10) ((r `mod` 10):xs) []
where r = x+y
add' rest (x:xs) (y:ys) = (r `mod` 10) : (add' (r `div` 10) xs ys)
where r = x+y+rest
List x must be bigger than list y but that's not a problem
add [5,7,8] [4,3,2] => [9,0,1,1] (correct)
add [1,2,3] [4,5,6] => [5,7,9,0] (correct)
You need to write a version of addLnat which accepts a carry parameter:
addLnat' c (x:xs) (y:ys) = d : addLnat c' xs ys
where d = if c+x+y > 9 then ... else ...
c' = ... the next carry bit ...
There are a lot more details and corner cases to consider, but this is the basic idea.
Finally,
addLnat xs ys = addLnat' 0 xs ys -- initially the carry is 0
I am new to ocaml and trying to write some code to generate all lists of number between two value.
For example, if I call this function generate, I want to obtain something like this :
let generate ~min ~max ~length (* Maybe other arguments *) =
(* The code *)
;;
generate ~min:0 ~max:3 ~length:4;;
Should return
[
[0;0;0];
[1;0;0];
[2;0;0];
[3;0;0];
[0;1;0];
And so on, to
[3;2;3];
[0;3;3];
[1;3;3];
[2;3;3];
[3;3;3];
]
I already tried code like this :
open Core.Std;;
type next_list =
| Complete of int list
| Partial of int list
| Result of (int array) list
;;
let rec next ~r ~min ~max ~l =
let detox = function | Partial a -> a | _ -> assert false in
match l with
| Partial (hd :: tl) when hd <= max -> Partial (hd + 1 :: tl)
| Partial (hd :: tl) when hd = max + 1 -> next ~r ~min ~max
~l:(Partial (min :: (detox (next ~r ~min ~max ~l:(Partial tl))) ))
| Complete (hd :: tl) when hd <= max -> next ~r:([l] :: r) ~min ~max
~l:(Complete (hd + 1 :: tl))
| Complete (hd :: tl) when hd = max + 1 -> next ~r ~min ~max
~l:(Complete (min :: (detox (next ~r ~min ~max ~l:(Partial tl)))))
(*| Partial [] -> next ~r ~min ~max ~l:(Result r)*)
| Result a -> Result a
It may be spread around several functions if necessary, that is not a problem.
I am also interested by non ocaml code or idea.
Thanks for your help.
This is my first question on Stackoverflow, do not hesitate to say if my question is unclear.
here some solution :
First, let's define that takes 2 lists l1 & l2 as input and that produces a list of list, where each element is l2 augmented by 1 element of l1 :
let enumerate l ll = List.fold ~init:[] ~f:(fun op x -> (x::ll)::op) l;;
enumerate [0;1;2;3] [4;5;6];;
- : int list list = [[3; 4; 5; 6]; [2; 4; 5; 6]; [1; 4; 5; 6]; [0; 4; 5; 6]]
Now generate :
let rec generate length ll =
if length=1 then List.fold ~init:[] ~f:(fun op x -> [x]::op) ll
else
let result = generate (length-1) ll in
List.fold ~init:[] ~f:(fun op x -> (enumerate ll x)#op) result;;
and usage is as follows :
generate 2 [1;2;3];; (* instead of generate ~min:1 ~max:3 ~length:2 *)
Some explanation :
List.fold ~init:[] ~f:(fun op x -> [x]::op) ll
=> this creates the initial list of list (singleton)
And the second : takes each of the list of length -1 and performs the enumeration.
Here's a hint:
let count_prefix low high lists =
???
let generate min max length =
let rec recur low high len =
if len = 0 then []
else count_prefix low high (recur low high (len - 1)) in
recur min max length
count_prefix should return a list that is the elements of lists prefixed with the numbers low to high. If lists is empty, it should return a list of lists containing the numbers low to high. That is:
count_prefix 0 3 [] => [[0]; [1]; [2]]
count_prefix 0 3 [[10];[20]] => [[0; 10]; [0; 20]; [1; 10]; [1; 20]; [2; 10]; [2; 20]]
Fill in the definition of count_prefix.