thoga31 571 Posted August 13, 2013 Report Share Posted August 13, 2013 (edited) Este desafio tem como principal público-alvo os principiantes ou, porventura, aqueles que estão a começar a estudar uma nova LP. Objectivo: O desafio é simples: abrir um ficheiro e interpretar, por linha, apenas o primeiro caracter se e só se este for um dígito ou uma letra minúscula. No final, dever-se-á fazer o output da soma dos dígitos e o nº de vezes que cada letra apareceu (o output não deverá conter as letras que nunca apareceram). Exemplo I/O: Ficheiro: 5 alegria n 7 4 n 654321 1 007 yes! woow atchim Output: Sum = 23 'a' = 2 'n' = 2 'w' = 1 'y' = 1 Edited August 13, 2013 by thoga31 Knowledge is free! Link to post Share on other sites
pwseo 234 Posted August 14, 2013 Report Share Posted August 14, 2013 (edited) Aqui vai uma tentativa, em Haskell. Ainda estou a aprender a mexer com Monads e Arrows, por isso é natural que haja formas mais legíveis e compactas de resolver o problema. De qualquer modo, o principal é mesmo a função run, o resto é basicamente IO e imports. import Data.Char import Control.Arrow import Control.Monad.State import qualified Data.Map as M type StateType = (Int, M.Map Char Int) initState :: StateType initState = (0, M.empty) run :: [string] -> State StateType () run ls = mapM_ aux ls where aux (c:_) | isDigit c = modify $ first (+ (read [c])) | isLower c = modify $ second (M.insertWith (+) c 1) | otherwise = return () main :: IO () main = do input <- getInput let (s, m) = execState (run input) initState putStrLn $ "Sum = " ++ show s mapM_ (putStrLn . f) $ M.toList m where getInput = liftM lines $ getContents f (k,v) = show k ++ " = " ++ show v EDIT: Alterei o código para algo que gostei mais, visualmente. EDIT2: Aceitar apenas dígitos e letras minúsculas Edited August 14, 2013 by pwseo Link to post Share on other sites
thoga31 571 Posted August 14, 2013 Author Report Share Posted August 14, 2013 @pwseo, tu conseguiste dar a volta ao problema de uma forma bastante complexa (do ponto de vista "mais comum"). Monads? Arrows? States? Contudo, é uma solução bastante interessante do ponto de vista haskelliano, sem dúvida. Só uma coisa: onde colocaste a condição de só serem permitidas letras minúsculas? Eu vejo a condição para os dígitos, mas não vejo o resto. De cabeça, se eu tiver uma linha a começar por "A", ele adiciona ao Map este caracter, e ele devia ser ignorado, assim como símbolos (!@#%...) Bom, eu decidi desenferrujar todos os meus conhecimentos básicos, e aqui vão as linguagens em que pelo menos cujas bases eu conheço... main :: IO() main = do contents <- readFile "desafio.txt" putStrLn $ solveit contents solveit = solve Map.empty 0 . map (head) . words where solve :: Map.Map Char Int -> Int -> String -> String solve alpha sumdig [] = "Sum = " ++ (show sumdig) ++ "\n" ++ (unlines . map (\(x,y) -> show x ++ " = " ++ show y) $ Map.toList alpha) solve alpha sumdig (x:xs) | Char.isLower x = case Map.lookup x alpha of Just n -> solve (Map.insert x (n+1) alpha) sumdig xs Nothing -> solve (Map.insert x 1 alpha) sumdig xs | Char.isDigit x = solve alpha (Char.digitToInt x + sumdig) xs | otherwise = solve alpha sumdig xs def solveit(file_name = "desafio.txt"): f = open(file_name, "r") contents = [i[0] for i in f.readlines() if (ord(i[0]) >= ord('a') or ord(i[0]) <= ord('z')) or (ord(i[0]) >= ord('0') or ord(i[0]) <= ord('9'))] f.close() sumdigit = 0 alpha = [0 for i in range(26)] for i in contents: if ord(i) >= ord('0') and ord(i) <= ord('9'): sumdigit += int(i) else: alpha[ord(i) - ord('a')] += 1 result = "Sum = {0}\n".format(sumdigit) for i in range(0,26): if alpha[i] != 0: result += "'{0}' = {1}\n".format(chr(i + ord('a')), alpha[i]) return result if __name__ == "__main__": print(solveit()) input() # pausa (para Windows) program challenge9; type TLowAlpha = 'a'..'z'; const LOWALPHA : set of char = ['a'..'z']; DIGITS : set of char = ['0'..'9']; FILE_NAME = 'desafio.txt'; var alpha : array[TLowAlpha] of byte = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); i : TLowAlpha; sumdigit : smallint = 0; f : text; s : string = ''; begin assign(f, FILE_NAME); reset(f); while not eof(f) do begin readln(f, s); if s[1] in DIGITS then inc(sumdigit, ord(s[1]) - ord('0')) else if s[1] in LOWALPHA then inc(alpha[s[1]]); end; close(f); writeln('Sum = ', sumdigit); for i := 'a' to 'z' do if alpha[i] <> 0 then writeln(i, ' = ', alpha[i]); readln; // pausa end. #include <stdio.h> #include <stdlib.h> #include <ctype.h> #define MAX_STR 2 #define ALPHA_LEN 26 int main(void) { short int sumdigit = 0; short int alpha[ALPHA_LEN] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; char s[2]; int i; FILE *f; f = fopen("desafio.txt", "r"); while (fscanf(f, "%s", s) != EOF) { if (isdigit(s[0])) sumdigit += (short) s[0] - (short) '0'; else if (isalpha(s[0])) if (islower(s[0])) alpha[(short) s[0] - (short) 'a']++; } fclose(f); printf("Sum = %hd\n", sumdigit); for(i=0; i < ALPHA_LEN; i++) { if (alpha[i] != 0) printf("%c = %hd\n", (char) (i + (short) 'a'), alpha[i]); } getchar(); /* pausa, só mais para o Windows */ } Module Module1 Sub Main() Dim file_name As String = "desafio.txt" Dim f As New IO.StreamReader(file_name) Dim ch As Char Dim sumdigit As UInt16 = 0 Dim alpha() As UInt16 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} While Not f.EndOfStream ch = f.ReadLine()(0) If Char.IsDigit(ch) Then sumdigit += Convert.ToInt16(ch) ElseIf Char.IsLetter(ch) AndAlso Char.isLower(ch) Then alpha(Asc(ch) - Asc("a"c)) += 1 End If End While Console.WriteLine("Sum = {0}", sumdigit) For i As UInt16 = 0 To alpha.Length - 1 If alpha(i) <> 0 Then Console.WriteLine("'{0}' = {1}", Chr(i + Asc("a"c)), alpha(i)) End If Next Console.ReadKey(True) End Sub End Module Knowledge is free! Link to post Share on other sites
pwseo 234 Posted August 14, 2013 Report Share Posted August 14, 2013 (edited) Estava distraído, não reparei nessa restrição (como o teste que tinhas dado tinha o output correcto no meu caso, não reparei). Mas basta adicionar o ramo correspondente ao código... Quanto à minha solução, apesar de "teoricamente complexa" se reparares está muito legível, pelo menos na minha opinião Temos uma função que claramente trata do algoritmo por detrás do problema e deixamos a apresentação do resultado toda para a main. EDIT: Alterei o código. Edited August 14, 2013 by pwseo Link to post Share on other sites
thoga31 571 Posted August 14, 2013 Author Report Share Posted August 14, 2013 Quanto à minha solução, apesar de "teoricamente complexa" se reparares está muito legível, pelo menos na minha opinião Temos uma função que claramente trata do algoritmo por detrás do problema e deixamos a apresentação do resultado toda para a main. Pois, como eu ainda não sou propriamente um especialista em Haskell e no tratamento I/O de dados, deixei a apresentação para a própria função que assim devolve uma String. Mas de facto não será nada difícil adaptar a main para receber os dados de outra forma e tratá-los. Mas agora fica assim, já há soluções em Haskell de sobra. Knowledge is free! Link to post Share on other sites
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now