Как я могу пройти через два файла одновременно в Perl? - PullRequest
8 голосов
/ 23 марта 2010

У меня есть два текстовых файла, которые содержат столбчатые данные сорта 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
...

Вместо чтения одного из двух файлов в хеш-таблицу, что запрещено из-заограничения памяти, что я хотел бы сделать, это пошагово проходить по двум файлам одновременно.

Это означает, что я хотел бы выполнять потоковую передачу по строкам A или B и сравниватьposition значения.

Если две позиции равны, то я выполняю расчет значений, связанных с этой позицией.

В противном случае, если позиции не равны, я перемещаюсь по строкам файла A или файла B до тех пор, пока позиции не станут равными (когда я снова выполню мои вычисления) или пока не достигну EOF обоих файлов.

Есть ли способ сделать это в Perl?

Ответы [ 4 ]

6 голосов
/ 23 марта 2010

Похоже, проблема, на которую можно наткнуться, например, данные таблицы базы данных с ключами и значениями. Вот реализация псевдокода, предоставленного 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);

Надеюсь, это поможет!

4 голосов
/ 23 марта 2010

Если файлы отсортированы, просмотрите их в зависимости от того, какой из них занимает нижнюю позицию.

псевдокод:

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 голосов
/ 23 марта 2010

Для просмотра файлов вы можете использовать модуль ядра Tie :: File . Он представляет собой обычный текстовый файл в виде массива.

1 голос
/ 05 марта 2016

Вот быстрое решение. Если данные в обоих файлах в значительной степени эквивалентны (например, одинаковое количество строк), вам не нужно хранить их в хеш-таблицах Но я подумал, что было бы полезно, если бы вы зашифровали данные.

Код:

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";
     }
}

Я надеюсь, что это поможет, и дайте мне знать, если это полезно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...