[Rio-pm] Comparação de arquivos

breno breno em rio.pm.org
Quinta Novembro 22 19:30:35 PST 2012


2012/11/22 Aureliano Guedes <guedes_1000 em hotmail.com>:
> 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 como pares chave-valor, por exemplo:

my %miranda = (
   'hsa-miR-15a' => '...',
   'hsa-miR-16' => '...',
   ...
);

my %hybrid = (
   'hsa-miR-16-1*' => '...',
   'hsa-miR-17' => '...',
   ...
);

depois, para cada item em %miranda, se a chave também existir em
%hybrid, vc preenche o seu arquivo de saída com os valores que quiser,
do jeito que quiser. Com isso vc de quebra dispensa o Array::Uniq e
otimiza a sua lógica:

foreach my $mirna (keys $miranda) {
   if (exists $hybrid{$mirna}) {
      say "o mirna $mirna existe em ambos os arquivos!";
      say "miranda: $miranda{$mirna}";
      say "hybrid: $hybrid{$mirna}";
   }
}


[]s

-b


Mais detalhes sobre a lista de discussão Rio-pm