SEMA
SEMA

Reputation: 83

How can I count Integers in a List of String. Haskell

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

Answers (6)

Landei
Landei

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

Alyona Bahaleisha
Alyona Bahaleisha

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

Dmytro Sirenko
Dmytro Sirenko

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

Boris
Boris

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 Chars, 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

Daniel Fischer
Daniel Fischer

Reputation: 183978

The basic principle is

  • count the items in a list with a given property

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

Tedil
Tedil

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

Related Questions