
Hello everyone , I wanted to do a small program which read a txt with fruit's name in each line and then print how many fruits I have of each type. something like these: apple apple and then [(apple,2)] I came up whit this import qualified Data.Map as Map import Data.List import System.IO main = do file <- readFile "fruits.txt" let answer = proccessFile $ lines file putStrLn (show answer) proccessFile :: [String] -> [(String,Int)] proccessFile file = Map.toAscList $ parseFile Map.empty file where parseFile fruits [] = fruits parseFile fruits_map (x:xs) = parseFile (Map.insertWith (+) x 1 fruits_map) xs It works, but I would like to know how would you do it ?, Share different points of view, different code. Was it a good idea to use a Map ?, Did I separate the code in a proper way, I mean pure - impure ? How can we improve the performance ? Best Regards for everyone. Adolfo

On Thu, Feb 19, 2009 at 3:15 PM, Adolfo Builes
Hello everyone , I wanted to do a small program which read a txt with fruit's name in each line and then print how many fruits I have of each type. something like these: apple apple
and then
[(apple,2)]
I came up whit this
import qualified Data.Map as Map import Data.List import System.IO
main = do file <- readFile "fruits.txt" let answer = proccessFile $ lines file
putStrLn (show answer)
proccessFile :: [String] -> [(String,Int)] proccessFile file = Map.toAscList $ parseFile Map.empty file where parseFile fruits [] = fruits parseFile fruits_map (x:xs) = parseFile (Map.insertWith (+) x 1 fruits_map) xs
It works, but I would like to know how would you do it ?, Share different points of view, different code. Was it a good idea to use a Map ?, Did I separate the code in a proper way, I mean pure - impure ? How can we improve the performance ?
Best Regards for everyone.
Adolfo
You spelled "process" incorrectly ;). Not a big deal of course, just makes your code a bit cleaner-looking. In terms of actual code, I think "proccessFruits" could probably be rewritten more clearly (and perhaps more efficiently, due to rewrite rules) using a fold. You might also check out the "group" function from Data.List, although that approach would probably be a bit slower. Hope that helps. Alex

Adolfo Builes wrote:
I wanted to do a small program which read a txt with fruit's name in each line and then print how many fruits I have of each type. something like these: apple apple
and then
[(apple,2)]
I came up with this
import qualified Data.Map as Map import Data.List import System.IO
main = do file <- readFile "fruits.txt" let answer = proccessFile $ lines file
putStrLn (show answer)
proccessFile :: [String] -> [(String,Int)] proccessFile file = Map.toAscList $ parseFile Map.empty file where parseFile fruits [] = fruits parseFile fruits_map (x:xs) = parseFile (Map.insertWith (+) x 1 fruits_map) xs
It works, but I would like to know how would you do it ?, Share different points of view, different code. Was it a good idea to use a Map ?, Did I separate the code in a proper way, I mean pure - impure ? How can we improve the performance ?
Looks good to me. :) Here's how I would write it main = print . process . lines =<< readFile "fruits.txt" process :: [String] -> [(String,Int)] process = Map.toAscList . foldl f Map.empty where f map x = Map.insertWith (+) x 1 map So, the parseFile function is best expressed as a left fold and function composition is good style. The above works fine for smaller files. If you have larger amounts of data, you will need a few strictness annotations or there will be a space leak. In this case, this means using the functions foldl' and Map.insertWith' instead of foldl and Map.insertWith But I wouldn't bother about that for now. Regards, apfelmus -- http://apfelmus.nfshost.com
participants (3)
-
Adolfo Builes
-
Alexander Dunlap
-
Heinrich Apfelmus