如何在Perl中同时浏览两个文件?

时间:2010-03-23 10:05:53

标签: perl file-io

我有两个文本文件,其中包含各种position - value的列式数据,按position排序。

以下是第一个文件(文件A)的示例:

100   1
101   1
102   0
103   2
104   1
...

以下是第二个文件(B)的示例:

20    0
21    0
...
100   2
101   1
192   3
193   1
...

不是将两个文件中的一个读入哈希表,而是由于内存限制而禁止使用,我想要的是逐步地同时遍历两个文件。

这意味着我想流式传输AB行并比较position个值。

如果两个位置相等,则我对与该位置相关的值进行计算。

否则,如果位置不相等,我会移动文件A或文件B的行,直到位置相等(当我再次执行计算时)或我达到两个文件的EOF

有没有办法在Perl中执行此操作?

4 个答案:

答案 0 :(得分:6)

看起来像是一个可能偶然发现的问题,例如带有键和值的数据库表数据。这是rjp提供的伪代码的实现。

#!/usr/bin/perl

use strict;
use warnings;

sub read_file_line {
  my $fh = shift;

  if ($fh and my $line = <$fh>) {
    chomp $line;
    return [ split(/\t/, $line) ];
  }
  return;
}

sub compute {
   # do something with the 2 values
}

open(my $f1, "file1");
open(my $f2, "file2");

my $pair1 = read_file_line($f1);
my $pair2 = read_file_line($f2);

while ($pair1 and $pair2) {
  if ($pair1->[0] < $pair2->[0]) {
    $pair1 = read_file_line($f1);
  } elsif ($pair2->[0] < $pair1->[0]) {
    $pair2 = read_file_line($f2);
  } else {
    compute($pair1->[1], $pair2->[1]);
    $pair1 = read_file_line($f1);
    $pair2 = read_file_line($f2);
  }
}

close($f1);
close($f2);

希望这有帮助!

答案 1 :(得分:4)

如果文件已排序,请根据哪个文件位于较低位置逐步执行。

伪代码:

read Apos, Aval from A # initial values
read Bpos, Bval from B 
until eof(A) or eof(B)
  if Apos == Bpos then
    compare()
    read Apos, Aval from A # advance both files to get a new position
    read Bpos, Bval from B
  fi
  if Apos < Bpos then read Apos, Aval from A
  if Bpos < Apos then read Bpos, Bval from B
end

你也可以使用join(1)来隔离具有共同位置的线条,并在闲暇时处理这些线条。

答案 2 :(得分:2)

对于循环文件,您可以使用核心Tie::File模块。它将常规文本文件表示为数组。

答案 3 :(得分:1)

这是一个快速解决方案。如果两个文件中的数据几乎相同(例如,行数相同),那么您并不需要存储在哈希表中。但我认为如果数据被扰乱将会有所帮助。

代码:

open(f1, "<data1");
open(f2, "<data2");
# initialize hashes
%data1 = ();
%data2 = ();
while(($line1 = <f1>) and ($line2 = <f2>)){
     chomp($line1);
     chomp($line2);
     # split fields 1 and 2 into an array
     @LINE1 = split(/\t/, $line1);
     @LINE2 = split(/\t/, $line2);
     # store data into hashes
     $data1{$LINE1[0]} = $LINE1[1];
     $data2{$LINE2[0]} = $LINE2[1];
     # compare column 2
     if ($data1{$LINE2[0]} == $data2{$LINE1[0]}){
           # compute something
           $new_val = $data1{$LINE2[0]} + $data2{$LINE1[0]};
           print $LINE1[0] . "\t" . $new_val . "\n";
     } else {
           print $LINE1[0] . "\t" . $data1{$LINE1[0]} . "\n";
     }
}

我希望它有所帮助,让我知道它是否有用。