Newsgroup: it.comp.lang.perl
Titolo: Ciclo while lento

Ciao a tutti ho un problema di lentezza sicuramente dovuto a dei cicli
inseriti che mi appesantiscono lo script. Qualcuno mi potrebbe buttare
un occhio :-) e suggerire se c'è un qualche sistema per velocizzare il
il tutto?
Lo script fa quest0:
apreun file di 65000 righe
lo memorizza in un array
apre un altro file di 500000 righe
cerca  ogni riga dell'array derivante dal file di 65000 righe nell
file da 500000. Se la trova la scrive su un altro file insieme ad
altri pezzettini presi in varie posizioni.
Per finire un ciclo il programma ci mette 35 secondi e quindi per
finire tutto ci vorrebbero 23 giorni
Vi incollo il file se qualcuno puo mi aiuti non vorrei passare 23
giorni a guardare lo schermo :-))
use Tie::File;
tie @solotranscritti,'Tie::File', "solotranscritti.txt";
close solotranscritti.txt;
@esoniintranscritto;
#open solotranscritti, "<", "solotranscritti.txt";
#while ($solotranscritti = <solotranscritti>)
#{
foreach $solotranscritti(@solotranscritti)
{
 print "questa e solotranscritti" ."\n";
 print $solotranscritti;
 open mart_exportposizioneEsoni, "<", "mart_exportposizioneEsoni.txt";
 while ($estraiesoni = <mart_exportposizioneEsoni>)
 {
  $confronto = substr($estraiesoni,16,15);
  $esoneestratto =  substr($estraiesoni,32,17);
  #print "questa e confronto" ."\n";
  #print $confronto . "\n";
  #print "questa è esoneestratto" ."\n";
  #print $esoneestratto . "\n";
  if ($solotranscritti eq $confronto)
  {
   #print "sisi"."\n";
   push (@esoniintranscritto, $esoneestratto);
   $gene = substr($estraiesoni,0,16);
  }
 }
  $esoniintranscritto2 = join (",",@esoniintranscritto);
  open transcrittoconEsoni, "+>>", "transcrittoconEsoni.txt";
  print transcrittoconEsoni $gene.",". $solotranscritti.",".
$esoniintranscritto2."\n";
  @esoniintranscritto = ();
 }

altri pezzettini presi in varie posizioni.
Soluzioni più efficienti possono essere: 1) metti tutto in due tabelle di
un database e fai tutti i confronti incrociati che vuoi; 2) usi un hash per
memorizzare le righe del file più piccolo.
Per la seconda soluzione:
   my %solotranscritti;
   open HSOLOTRANSCRITTI, '<', 'solotranscritti.txt';
   while (<HSOLOTRANSCRITTI>) {
     chomp;
     $solotranscritti{$_} = 1;
   }
   close HSOLOTRANSCRITTI;
   ...
   #apri l'altro file e cominci a scorrerlo riga per riga
   #ottenendo la stringa di confronto, non ho voglia di capire come
   ...
   if (exists($solotranscritti{$confronto})) {
       #la stringa di confronto era anche nel primo file
       #fai quindi tutti i tuoi giochini che non ho voglia di leggere
   }
   ....
La costruzione di una hash di 65000 elementi (o anche meno, se le righe si
ripetono) e la successiva ricerca sono molto efficienti e non dovrebbero
comportare problemi sulle macchine attuali (a meno che le righe non siano
molto lunghe).
La prima soluzione non dovrebbe aver bisogno di spiegazioni, al di là del
fatto che possa essere più o meno praticabile nel tuo caso.
Ciao.

il tutto?
Lo spiegň Perry Mason, in una puntata, dovevano confrontare una lista di 
molti numeri con un elenco telefonico...
1)Prendi il megafile, e creane uno temporaneo ordinato in base al campo 
estratto. (magari in questa fase estrai i soli campi che effettivamente ti 
servono).
Come fare? Semplice prendi tot caratteri del primo campo, poi tot per il 
secondo in modo da fare un file con righe di larghezza fissa, quindi usa il 
comando sort (attenzione a paddare i numerici - oppure prova 
open(MYINPUTFILE, "<filename.out");my(@lines) = <MYINPUTFILE>; @lines = 
sort(@lines);)
2)Prendi il piccolo file e creane uno temporaneo ordinato in base al campo 
estratto.
3) Ora apri entrambi i files e usa un loop che termina quando entrambi i 
files sono arrivati alla fine, procedi passo passo facendo avanzare quello 
con il campo da confrontare minore.
ripeti finoaquando filea e fileb entrambi a fineriga
  se campo(vara) = campo(varb)
      elaborariga(vara,varb)
      leggo prossima riga filea in vara
      leggo prossima riga fileb in varb
  seinvece vara < varb
      leggo prossima riga filea in vara
  altrimentiancora
      leggo prossima riga fileb in varb
fineciclo
Teoricamente moooolto piů veloce.
Aggiornaci sul risultato.
Ciao,
ScriptJus 

 fineciclo
Al termine del ciclo dovresti aggiungere di nuovo:
se campo(vara) = campo(varb)
    elaborariga(vara,varb)
Perchč il ciclo elabora le informazioni nell'iterazione successiva alla 
lettura dal file.
Probabilmente cosě č meglio:
vara=vuoto
varb=vuoto
ripeti finoaquando filea e fileb entrambi a fineriga
  se vara nonvuoto e campo(vara) = campo(varb)
      leggo prossima riga filea in vara
      leggo prossima riga fileb in varb
  seinvece campo(vara) < campo(varb)
      leggo prossima riga filea in vara
  seinvece campo(vara) > campo(varb)
      leggo prossima riga fileb in varb
  se campo(vara) = campo(varb)
      elaborariga(vara,varb)
 fineciclo
Facci sapere
Ciao,
ScriptJus 

 ScriptJus
Grazie a tutti
ScriptJus la tua soluzione era un po cmplicata per un newbie come me.
Ho provato la seconda soluzione suggeritami utilizzando grep al posto
di Exists e le cose vanno decisamente meglio
ci mette circa 3 secondi per riga
grazie ancora
Guido

ci mette circa 3 secondi per riga
E infatti ci deve mettere pochi secondi in tutto, non per riga. Hai fatto
evidentemente qualcosa di completamente diverso da quello che ti avevo
proposto.
Ciao.

 ci mette circa 3 secondi per riga
3 secondi?!
Se segui l'approccio di Giovanni (che non richiede l'uso di grep), non 
ci metti neanche 3 millisecondi per riga.
Se hai qualche dubbio sui dettagli implementativi, chiedi e ti sarà dato.

ci mette circa 3 secondi per riga
Sti cazzi!
Ma hai un computer a manovella?
Ciao,
ScriptJus 


ROTFL