Jump to content
thoga31

[Muito fácil] Interpretar um pequeno ficheiro

Recommended Posts

thoga31

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 by thoga31

Knowledge is free!

Share this post


Link to post
Share on other sites
pwseo

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 by pwseo

Share this post


Link to post
Share on other sites
thoga31

@pwseo, tu conseguiste dar a volta ao problema de uma forma bastante complexa (do ponto de vista "mais comum"). Monads? Arrows? States? :D

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... :D

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!

Share this post


Link to post
Share on other sites
pwseo

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 by pwseo

Share this post


Link to post
Share on other sites
thoga31

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. :D


Knowledge is free!

Share this post


Link to post
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.