10 de dezembro de 2006

Ubuntu Forums - desafio de programação semanal

Há dois dias atrás foi proposto no fórum internacional do Ubuntu um desafio de programação até bem simples. O objetivo do programa era gerar uma tabela de multiplicação 10x10, o exemplo a seguir ilustra bem isso:

1*1 1*2 1*3 ... 1*8 1*9 1*10
2*1 2*2 2*3 ... 2*8 2*9 2*10
...
9*1 9*2 9*3 ... 9*8 9*9 9*10
10*1 10*2 10*3 ... 10*8 10*9 10*10

O mais interessante foi ver as diferentes soluções em um variado número de linguagens. Vou listar e comentar algumas que eu vi por lá.

Python:
def table(x, y):
for i in range(x):
for j in range(y):
x = (i+1) * (j+1)
print "%4d" % x,
print
table(10,10)
Eu acredito que qualquer pessoa que entenda um pouco de programação independentemente da linguagem pode entender esse código. A clareza e simplicidade dessa solução para mim foi o seu ponto forte.

Ruby:
(1..10).each {|i| (1..10).each {|j| printf "%4s",(i*j)}; puts}
Eu não esqueci de colar nada, o código é só esse mesmo. One-liner para resolver :D. Com certeza o tamanho do código é o maior destaque da solução em Ruby. A idéia é semelhante a do programa em Python, mas a forma de implementação é bem diferente. O (1..10).each é um laço que vai de 1 até 10, diferentemente do programa anterior que usa uma lista de 0 a 9 (range(10)).

C:
#include <stdio.h>

int main(int argc, char **argv){
int i,j;
for(i=1;i<=10;i++){
for(j=1;j<=10;j++){
printf("%4d", i*j);
}
printf("\n");
}
}
A versão em C parece nada mais do que um Python complicado. Até a estrutura de "for"s é igual, mudando novamente o inicio que começa em 1 evitando aquele (i+1)*(j+1) do primeiro programa.

Java:
public class MultMatr
{
final public static void main(String[] args)
{
java.util.Scanner keys=new java.util.Scanner(System.in);
StringBuffer res=new StringBuffer();
System.out.print("Give dimension?:");
int dim=keys.nextInt();
for(int i=0;i<dim;i++)
{
int k=0;
for(int j=0;j<dim;j++)
{
k+=i+1;
res.append(k+"\t");
}
res.append("\n");
}
System.out.println(res.toString());
}
Depois dizem que as pessoas implicam com Java, está na cara que essa até agora foi a solução menos trivial, se bem que o valor da variável dim não é fixo, mas nem isso justifica. Continuo achando que para programas simples Java não é a melhor escolha.

A última coisa que eu quero é causar algum tipo de discussão sobre qual é a melhor linguagem, o principal motivo desse post é mostrar as diferentes soluções possíveis para um mesmo problema usando linguagens distintas. Quem quiser ver resoluções do problema para outras linguagens podem ir nesse post do fórum internacional do Ubuntu.

6 comentários:

  1. Divertido. fica aqui minha contribuição:

    Table[i*j, {i, 1, 10}, {j, 1, 10}]

    Isso é no Mathematica, da Wolfram Research.

    Abraços

    ResponderExcluir
  2. Boa... eu não conheço esse Mathematica mas ficou bem simples o resultado. Esse programa tem algo semelhante ao MatLab?

    Quem quiser dar mais exemplos em outras linguagens podem ficar a vontade para colocar nos comentários e/ou no post do fórum que eu linkei.

    ResponderExcluir
  3. O Matlab só faz calculo numérico. O Mathematica faz simbolico tb. Fora que tem infinitas features a mais, desde comunicacao com webservices, podes escrever em C/C++/Fortran/Java e linkar com as libs dele e vice versa, enfim, ao meu ver, bem superior ao Matlab.

    Mas gostos sao gostos :-)

    O grande problema é o preço. A licença de um ano sai por 2 mil dólares.

    Abraços.

    ResponderExcluir
  4. Bom, to postando aqui por que esse exemplo de Java ai nao tem nada a ver.
    Primeiro que nao tem nada de complexo, como dito, so pq tem mais linhas (desnecessarias e claro, como ler do teclado a dimensao e o numero inicial), e segundo porque usa um Buffer ao inves de concatenacao normal.

    Um exemplo em Java (otimizado para ser bem rapido):

    public class TabelaMultiplicacao{
    public static void main(String args[]){
    StringBuffer res = new StringBuffer();
    for (int i=1; i<=10; i++){
    for (int j=1; j<=10; j++){
    res.append(i+"*"+j+"\t");
    }
    res.append("\n");
    }
    System.out.println(res.toString());
    }
    }


    Vantagens do codigo sobre os outros: Usa um buffer para que tudo seja concatenado de 1 so vez, ao inves de concatenar por cada bloco. Tente fazer isso para uma tabela de dimensao 1000 e vera q isso faz a diferenca.


    Sem o StringBuffer ele seria assim (mais simples ainda, mas que implica numa perde de desempenho):

    public class TabelaMultiplicacao{
    public static void main(String args[]){
    String res = "";
    for (int i=1; i<=10; i++){
    for (int j=1; j<=10; j++){
    res = res + i+"*"+j+"\t";
    }
    res = res + "\n";
    }
    System.out.println(res);
    }
    }


    Portanto temos que tomar cuidado em falar sempre que o Java e complexo e nos perguntar: Queremos fazer um codigo legivel e otimizado com um pouco mais de esforco ou pode ser um codigo "porco", com gambiarra?

    ResponderExcluir
  5. Eai Lucas, gostei de ver o exemplo e a explicação. Sobre o StringBuffer você está mais do que correto, usá-lo no lugar de ficar concatenando Strings comuns é bem mais rápido.

    Claro que o código em Java não chega a ser complicado, o desafio em si também não é complicado. A leve cutucada que eu dei na linguagem foi pelo fato do exemplo postado no fórum e reproduzido por mim no blog ser o menos amigável de todos na minha opinião.

    Eu ainda penso que você pode fazer um código simples, sem precisar escrever linhas desnecessárias e nem por isso ser gambiarra.

    Quero deixar claro que eu não tenho nada contra nenhuma linguagem, eu apenas comentei sobre as soluções. Eu inclusive uso Java bastante, mesmo não sendo muito experiente.

    ResponderExcluir
  6. fiz assim em C:

    #include
    main()
    {
    int controle = 1, numero = 1, multi;
    while(numero <= 10)
    {
    for(controle >= 1; controle <=10; controle++)
    {
    multi = controle*numero;
    printf("%i ", multi);
    }
    numero++;
    controle = 1;
    }
    }

    ResponderExcluir