Re: [Rio-pm] Comparação de arquivos

2012-11-23 Thread Aureliano Guedes

Breno, valeu mesmo por mais dicas preciosas, dessa ultima forma que me falou 
foi bem mais facil codar. A logica foi super-simples mas não fui capaz de 
pensar nisso sozinho.

Mais ainda estou com um problema e uma duvida.

- devido o $/ o print não esta saindo completo, vem faltando parte do 
documento, justamente o valor de $/. Como resolver isso?

- Não entendo o que você quer dizer com "testar o valor de retorno de funções 
como open()"?

Em fim segue o codigo: http://pastebin.com/KH2bAGWU

Desconcidere o seu modulo Data::Printer, usei ele para testar o hash e esqueci 
de tirar do codigo depois, XD. (Otimo modulo).

> Date: Fri, 23 Nov 2012 01:30:35 -0200
> From: br...@rio.pm.org
> To: rio-pm@pm.org
> Subject: Re: [Rio-pm] Comparação de arquivos
> 
> 2012/11/22 Aureliano Guedes :
> > Opa, obrigado pela ajuda e pelas preciosas dicas.
> >
> > - Não achei uma função no List::MoreUtils que fizesse o mesmo que o dups do
> > Array::Uniq, tem alguma função no List::MoreUtils que crie um terceiro array
> > apenas com itens que outros dois ou mais arrays tem em igual?
> >
> 
> Tem razão, Aureliano. A função dup() do List::MoreUtils remove
> duplicatas, não as retorna para você. Se o Array::Uniq te atende
> então, maravilha. Se preferir resolver direto no Perl, seguem algumas
> alternativas (só por desencargo mesmo):
> 
> 
> my %duplicadas = ();
> my %visitadas  = ();
> foreach (@a, @b) {
>   $visitadas{$_}++ && $duplicadas{$_}++;
> }
> my @resultado = sort keys %duplicadas;
> 
> my @resultado = ();
> foreach my $item (sort @b) {
>   push @resultado, $item if any { $item eq $_ } @a;
> }
> 
> my %visitadas = ();
> my @resultado = sort grep { $visitadas{$_}++ == 1 } @a, @b;
> 
> 
> > - Particularmente não vi vantagem em usar o Path::Class, para meu caso qual
> > seria a vantagem?
> >
> 
> O Path::Class resolve um monte de coisas pra vc. Hoje você abre
> arquivos no mesmo diretório. Se amanhã quiser usar diretórios
> diferentes, cada sistema tem um separador diferente ('/', '\', etc). O
> Path::Class faz isso pra vc. Outro motivo é a preguiça. Escrever:
> 
> my $fh = file( $nome_do_arquivo )->openr;
> 
> é a mesma coisa que escrever:
> 
> open my $fh, '<', $nome_do_arquivo
>   or Carp::croak "error opening file $nome_do_arquivo: $!\n";
> 
> Se vc só vai fazer isso, tudo bem. Mas quando começa a ter que passear
> e manipular arquivos e diretórios, acredite: faz toda a diferença :)
> 
> Independente do que escolher, lembre-se sempre de testar o valor de
> retorno de funções como open(), bem como usar open() sempre com 3
> argumentos!
> 
> > - Quanto a criar um modulo fazendo o que as subs fazem, depois vou pensar
> > nessa hipotese, mais um modulo para o BioPerl não faz mal.
> >
> 
> Maravilha!
> 
> > - Quanto ao que você falou no item 11:
> >
> > - Continuei usando barewords pois não deu certo usando strings, por algum
> > motivo que não sei por que? (Afinal qual o problema das barewords?)
> >
> 
> Não diga "não deu certo", nos diga o erro!
> 
> Barewords são problemáticas por diversos motivos, o principal deles é
> que são globais. Lembra dos bugs de "ação à distância"? Pois é, se vc
> usar sem querer o mesmo nome de file handle (digamos, "FH", "FILE",
> "ARQ" ou equivalente) em diferentes lugares, seu programa vai se
> comportar de maneira estranha e vc não vai ter idéia do motivo. Por
> mais que você ache que seu programa é pequeno e controlável agora, é o
> tipo de boa prática que compensa *muito* a medida que o programa
> escala (ou o tempo passa e vc tem q manter o código 6 meses depois).
> 
> Variáveis podem ser utilizadas como filehandle desde o Perl 5.6.0, de
> 12 anos atrás. Desde então, esse tem sido o meio recomendado para
> lidar com arquivos - a menos que vc esteja fazendo um oneliner rápido
> na linha de comando, ou lidando com handles nativos como STDIN,
> STDOUT, DATA, etc.
> 
> >
> > "11) No seu código você abre os arquivos 'hybrid.txt' e 'miranda.txt'
> > duas vezes para leitura. Isso normalmente significa que você poderia
> > ter colocado tudo numa estrutura de fácil acesso e manipulação, e lido
> > o arquivo apenas uma vez (operações de E/S costumam ser bem mais
> > pesadas do que manipulação em memória). Dica: sempre que tiver mais de
> > um while() ou foreach() varrendo a mesma estrutura para ler dados, é
> > bem possível que você possa otimizar e deixar mais claro seu algoritmo
> > fazendo a varredura apenas uma vez."
> >
> > Isso me preocupou, veja bem, não consegui pensar em uma forma de varrer o
> > arquivo fazendo o que preciso apenas em um laço.
> > parsin_h e parsin_m extraem um valor que são gravados em array, @inh e @inm
> > respectivamente, depois um terceiro array (@in) é criado apenas com os
> > valores que @inh e @inm tem em comum.
> > Os valores de @in são a referencia de "o que" eu quero extrair dos arquivos
> > hybrid.txt e miranda.txt.
> >
> 
> Você pode por exemplo passar uma vez só em cada arquivo e armazenar os
> elementos co

Re: [Rio-pm] Comparação de arquivos

2012-11-23 Thread breno
2012/11/23 Aureliano Guedes :
> Breno, valeu mesmo por mais dicas preciosas, dessa ultima forma que me falou
> foi bem mais facil codar. A logica foi super-simples mas não fui capaz de
> pensar nisso sozinho.
>
> Mais ainda estou com um problema e uma duvida.
>
> - devido o $/ o print não esta saindo completo, vem faltando parte do
> documento, justamente o valor de $/. Como resolver isso?
>

Várias formas diferentes. Seguem duas de exemplo:

1) concatenar $/ ao final da sua string na hora de atribuir;
2) trocar de abordagem, fazendo seu parser ler linha a linha (sem
modificar $/) e ir acumulando as linhas até encontrar um símbolo que
indique nova entrada. Eu prefiro essa abordagem pq facilita (pra mim)
a compreensão e ajuda (para todos) a alteração/extensão futura do seu
parser, caso vc queira em algum momento separar os valores de cada
registro em subgrupos, por exemplo.

Note ainda que, se for possivel interagir com os dados dos programas
internos mais diretamente (por exemplo, através de wrappers de alguma
API) em vez de analisando essa saída, você provavelmente conseguirá
mais flexibilidade na leitura e interpretação dos dados de saida.

> - Não entendo o que você quer dizer com "testar o valor de retorno de
> funções como open()"?
>

Funções que acessam o sistema de arquivos tem uma propensão muito
maior em falhar, por motivos como muitos arquivos abertos, erro de
disco, arquivo não encontrado, só pra citar alguns. Digamos, por
exemplo, que você faça:

  open my $fh, '<', 'miranda.txt';
  while (my $linha = <$fh>) {
 print $linha;
  }
  close $fh;

E se vc rodar o programa de um diretório errado e, por isso, ele não
achar o 'miranda.txt'? Você não vai receber nenhuma resposta (porque
está ignorando o valor de retorno da open()), seu programa vai
continuar rodando como se nada tivesse acontecido, e operações com o
handle vão falhar silenciosamente. Por isso escrevemos:

  open my $fh, '<', 'miranda.txt' or die $!;

o "or die" testa o valor de retorno da função open(). Se open() falhou
ao abrir o arquivo, ela retorna undef e registra o erro na variável
especial $!. O que o "or die" está fazendo é: "rode o open() ou, se o
open() falhar, morra exibindo a mensagem em $!". Entendeu?

A maioria das pessoas bota o "or die" pelo menos depois de um open(),
mas a verdade é que várias outras funções podem falhar sem vc ficar
sabendo. Por isso o ideal é vc testar o valor de retorno de todas as
funções, em especial as que envolvem I/O. Mas convenhamos, isso é
chatíssimo. Já pensou fazer "print $fh q{lalala} or die 'erro
escrevendo em arquivo'" cada vez que for fazer um print? Quando vc usa
o pragma autodie, ele muda essas funções para que elas gerem excessões
fatais caso falhem, de modo que tudo que vc precisa fazer é escrever:

   use autodie;

no início do seu programa e não se preocupar mais. A partir daí, não
precisa botar "or die" nenhum. Sempre que a função falhar (seja
open(), close(), print() e várias outras) ela vai gerar uma exceção
fatal imediatamente, exibindo qual foi o erro encontrado e em qual
linha. Isso ajuda muito a identificar casos extremos e evita que o seu
programa continue a execução em um estado inconsistente.

Como dizem os Klingons:

bIlujDI' yIchegh()Qo'; yIHegh()!
(it is better to die() than to return() in failure)


Mais detalhes sobre o problema e sobre o autodie =>
http://perltraining.com.au/tips/2008-08-20.html

> Em fim segue o codigo: http://pastebin.com/KH2bAGWU
>

Eu faria ainda uma mudança imediata: remover as globais. Em vez de ter :

my %h = ();
my %m = ();

lá em cima, é melhor fazer, dentro da sua main:

my %h = hybrid();
my %m = miranda();

Isso compartimentaliza e isola as suas variáveis, que agora só estarão
definidas no bloco que de fato as utiliza. Se o seu programa crescer,
vc não vai precisar se preocupar com globais acumulando e facilitando
problemas de ação à distância.

> Desconcidere o seu modulo Data::Printer, usei ele para testar o hash e
> esqueci de tirar do codigo depois, XD. (Otimo modulo).
>

Que bom que gostou =)

[]s

-b
___
Rio-pm mailing list
Rio-pm@pm.org
http://mail.pm.org/mailman/listinfo/rio-pm