Reputation: 83
There is a list of String ["f", "1", "h", "6", "b", "7"].
How can I count Int in this list?
Now I have this algorithm but it's not so good.
import Data.Char
let listOfStrings = ["f", "1", "h", "6", "b", "7"]
let convertedString = "f1h6b7"
let listOfInt = map (\x -> read [x]::Int) (filter (\x -> isDigit x) convertedString)
length listOfInt
Prelude> 3
Besides, I can't convert listOfStrings to one string. This algorithm doesn't even work properly
Can you help me with optimization?
Upvotes: 2
Views: 2897
Reputation: 54584
I find it often useful to convert Bool
to 0 or 1 using fromEnum
:
import Data.Char
countInts = sum . map (fromEnum . isNumber) . concat
Upvotes: 0
Reputation: 11
I'm sure the best answer for you will be
import Data.List (foldl')
import Data.Char (isNumber)
countNumb l = foldl' (\x y -> x+1) 0 (filter isNumber l)
here we check if char is number and count them
Ps. This will work for ['f', '1', 'h', '6', 'b', '7']
.
Upvotes: 0
Reputation: 5083
1) Use reads :: Reads Int
(this expression is just reads :: String -> [(Int, String)]
in disguise) to test whether a string is a representation of an integer value:
isNumber :: String -> Bool
isNumber s = case (reads s) :: [(Int, String)] of
[(_, "")] -> True
_ -> False
Why reads
? Because it returns additional information about parsing process from which we can conclude if it was successful. read :: Int
would just throw an exception.
2) then filter a list of strings with it and take its length:
intsCount :: [String] -> Int
intsCount = length . filter isNumber
Upvotes: 5
Reputation: 5176
Your code can be rewritten as:
import Data.Char
let listOfStrings = ["f", "1", "h", "6", "b", "7"]
let convertedString = concat listOfStrings
let listOfInts = map digitToInt (filter isDigit convertedString)
length listOfInts
Prelude> 3
To go from a list of strings to just a single string, just use concat
. Concat takes a list of lists, and returns a single list, with all the elements of the lists after each other, and since a string is a list of Char
s, concat
in this case takes a list of lists of Char
, and returns a single list of Char
, (aka a string).
The filter is simplified from using \x -> isDigit x
to just isDigit
. This is exactly the same function.
I read the digits using digitToInt
instead of \x -> read [x] :: Int
Notice that if you only want to find the number of digits in convertedString
, you can do:
let listOfDigits = filter isDigit convertedString
length listOfDigits
Prelude> 3
Upvotes: 0
Reputation: 183978
The basic principle is
That's solved by some Prelude
functions quite easily:
countItemsWith :: (a -> Bool) -> [a] -> Int
countItemsWith property list = length $ filter property list
All that remains is to find a good expression to determine whether a String
is the representation of an integer. We could write our own test, but we can also re-use a Prelude
function for that,
isIntegerRepresentation :: String -> Bool
isIntegerRepresentation s = case reads s :: [(Integer,[Char])] of
[(_,"")] -> True
_ -> False
Upvotes: 2
Reputation: 1933
concat
concatenates multiple lists, so concat listOfStrings
will result in "f1h6b7"
.
If you only want to count positive integers, you could try something along the lines of
countInts (x:xs) = if isDigit x then 1 + countInts xs else countInts xs
where (x:xs)
is a pattern for a list with head element x
and a tail of xs
. (So this will work for convertedString
because it is a list of characters [Char]
but not for listOfStrings
because it is actually [String]
which can be expanded to [[Char]]
).
What is the actual input you've got? listOfStrings
or convertedString
?
Upvotes: 0