3

私は単純なループに取り組んでいますが、機能していません。共通の ID に基づいて比較する 2 つのファイルがあります。最初の結果と最初の結果のみを出力するため、機能します。そのため、残りのファイル (または出力に最初のファイルのすべての行が含まれているため、最後のファイル) をループしていません。最初のファイルのすべての行を出力しますが、2 番目のファイルの最初の結果のみを出力ファイルに追加します。明確にするための私のコードは次のとおりです。

use strict;
use warnings;

my $inputfile1 = shift || die "Give input & output!\n";
my $inputfile2 = shift || die "Give input & output!\n";
my $outputfile = shift || die "Give input!\n";

open my $INFILE1,  '<', $inputfile1 or die "In use / Not found :$!\n";
open my $INFILE2,  '<', $inputfile2 or die "In use / Not found :$!\n";
open my $OUTFILE,  '>', $outputfile or die "In use / Not found :$!\n";

while (<$INFILE1>) {
s/"//g;
my @elements = split /;/, $_;

    while (<$INFILE2>) {
        s/"//g;
        my @loopelements = split /;/, $_;

            if ($elements[11] eq $loopelements[0]){
                $elements[12] = $loopelements[1];
                $elements[13] = $loopelements[2];
                }
    }

my $output_line = join(";", @elements);
print $OUTFILE $output_line;
#print "\n"
}

close $INFILE1;
close $INFILE2;
close $OUTFILE;

exit 0;

私の最初の試みはこのコードで、部分的に機能しました。なぜ ?: 途中でクラッシュします。出力ファイルを確認すると、途中で停止しました。理由がわからない!余談ですが、以下のものは効率が悪いと思いますか、それとも両方のより良い代替手段はありますか?

$inputfile1=$ARGV[0];  
$inputfile2=$ARGV[1]; 
$outputfile1=$ARGV[2];

open(INFILE1,$inputfile1) || die "Give input & output :$!\n";
open(INFILE2,$inputfile2) || die "Give input & output :$!\n";
open(OUTFILE_1,">$outputfile1") || die "Give input & output :$!\n";

$i = 0;
$j = 0;

@infile1=<INFILE1>;
@infile2=<INFILE2>;

foreach ( @infile1 )
  {
  @elements = split(";",$infile1[$i]);
  $j=0;

  foreach ( @infile2 )
      {
      @loopelements = split(";",$infile2[$j]);

      if ($elements[11] eq $loopelements[0]){
         $elements[12] = $loopelements[1];
         $elements[13] = $loopelements[2];
         $printen = 1;
         last;
        }

      $j = $j+1;
      }

  @elements = join(";",@elements);
  print "$i\r";
  if ($printen == 1) { print OUTFILE_1 "@elements"; };

  $i = $i+1;
  }
close(INFILE1);
close(INFILE2);
close(OUTFILE_1); 

それで、誰かが私のコードのどこが間違っているのか指摘できますか?

4

2 に答える 2

3
  1. 最初のファイルの最初の行は、外側のループの最初の繰り返しで読み取られます。

  2. この最初の繰り返しの間に、2 番目のファイルのすべての行が内側のループで読み取られます。

  3. 次に、外側のループの最初の繰り返しが終了します。

  4. ここで、外側のループの 2 回目の反復が始まります。もう読み取る必要のある 2 番目のファイルの行が残っていますか? いいえ。

問題を最も単純なものに分解すると、コメントが隣にある 2 つの行により、プログラムは毎回2 番目のファイルの行をループします。

use warnings;

my $inputfile1 = shift || die "Give input & output!\n";
my $inputfile2 = shift || die "Give input & output!\n";

open my $INFILE1,  '<', $inputfile1 or die "In use / Not found :$!\n";
open my $INFILE2,  '<', $inputfile2 or die "In use / Not found :$!\n";

my $infile2_pos = tell $INFILE2; # remember start position

while (<$INFILE1>) {

  print;

  seek $INFILE2, $infile2_pos, 0; # seek the start position

  while (<$INFILE2>) {
    print;
  }
}

これが遅すぎる場合は、次の 2 つの方法があります。

  1. 外側のループでより大きなファイルを読み取ります (これにより速度が向上する理由はご存じだと思います)。
  2. 小さい方のファイルを最初にアレイに読み込むので、ディスク I/O を繰り返し実行する必要がありません。

これが意味することは次のとおりです。

open my $BIGFILE,  '<', $bigfile or die "In use / Not found :$!\n";
open my $SMALLFILE,  '<', $smallfile or die "In use / Not found :$!\n";

my @smallfile_array = <$SMALLFILE>;

while (<$BIGFILE>) {

  print;

  foreach (@smallfile_array) {
    print;
  }
}
于 2012-07-10T08:54:16.227 に答える
0

コードの問題については、@ArjunShankar の投稿を確認してください。私は別のアプローチを投稿するのではなく、同じことをしていません。

use strict 
open my $IFILE1,  '< myfile.csv' or die $!;
open my $IFILE2,  '< myfile.csv' or die $!;

my %File1 = map {s/"//g; (join '-',(split /,/)[0,2]),$_} <$IFILE1>;
my %File2 = map {s/"//g; (join '-',(split /,/)[0,2]),$_} <$IFILE2>;

foreach my $Key (keys %File1) {
    print "REQD-DETAILS" if exists $File2{$Key};
}
于 2012-07-10T11:44:14.203 に答える