benharris
benharris

Reputation: 597

In Haskell how to count the number of a specific Int in a list

I am trying to create a function countElems that takes an Int and a [Int] and returns how many of that specific Int is in the list. So far I have:

countElems :: Int -> [Int] -> Int
countElems n (x:xs)
| xs == []   = 0
| n == x     = 1 + countElems n xs
| n /= x     = countElems n xs

When run, this seems to work, but on further inspection, if you enter countElems 9 [5, 3, 9, 3, 9] the output is 1 instead of 2. I can see this is because it checks that xs == [] before seeing if n == x resulting in the incorrect output, but if I swap those two cases around is says Non-exhaustive pattern.

Edit after further thought:

I could eliminate the error @user2407038 posted with this code:

countElems :: Int -> [Int] -> Int
countElems _ [] = 0
countElems n (x:xs)
| n == x     = 1 + countElems n xs
| n /= x     = countElems n xs

It looks a less elegant but works just the same?

Upvotes: 0

Views: 3993

Answers (4)

Ingo
Ingo

Reputation: 36329

Another one without any recursive clauses:

countElem e = length . filter (e ==)

Upvotes: 6

JBarberU
JBarberU

Reputation: 1029

You could also write it using map:

countElems :: Int -> [Int] -> Int
countElems n xs = sum $ map (fromEnum . (==n)) xs

Upvotes: 0

user2407038
user2407038

Reputation: 14578

Your function is non-exhaustive regardless of which order you place the guards in. Consider countElems 9 []. This is an error since no pattern matches the empty list. (Maybe this is desired behaviour for your case - but typically errors are bad). Consider using pattern matching here:

countElems n (x:xs) = fromEnum (n == x) + countElems n xs
countElems _ []     = 0

The fromEnum avoids if which I like, but you don't have to use it.

There is probably no need to use explicit recursion here. Try \x = length . filter (==x).

Upvotes: 2

phimuemue
phimuemue

Reputation: 35983

In your first check (xs == [] = 0) you forget to check whether x==n in which case the result should be 1 instead of 0:

countElems n (x:xs)
| xs == []   = if x==n then 1 else 0
| n == x     = 1 + countElems n xs
| n /= x     = countElems n xs

Another (probably more straightforward) implementation might look at the list as a whole:

cE n [] = 0
cE n (x:xs) = (if n==x then 1 else 0) + (cE n xs)

Upvotes: 2

Related Questions