2012-05-03 16 views
0

私は一緒に整列する必要がある2つのタブで区切られたファイルを持っています。例えば:類似の列を持つ2つのファイルをマージする

File 1:  File 2: 
AAA 123  BBB 345 
BBB 345  CCC 333 
CCC 333  DDD 444 

(これらは潜在的に、数千行の大きなファイルです!)私がやりたい何

は、出力は次のようになり持っていることです。

AAA 123 
BBB 345 BBB 345 
CCC 333 CCC 333 
     DDD 444 

好ましくはI perlではこれをやりたがっていますが、どうしたらよいかわかりません。どのような助けにも大いに役立つでしょう。ファイルがソートされていると仮定すると、

+0

をHTTPを見てください://stackoverflow.com/questions/4960275/how-can-match-records-in-two-files-using-perl –

+0

本当に毎回行ラベルを繰り返す必要がありますか? arrayrefsのハッシュを構築するのは簡単でしょう。 –

答えて

0

sub get { 
    my ($fh) = @_; 
    my $line = <$fh>; 
    return() if !defined($line); 
    return split(' ', $line); 
} 

my ($key1, $val1) = get($fh1); 
my ($key2, $val2) = get($fh2); 

while (defined($key1) && defined($key2)) { 
    if ($key1 lt $key2) { 
     print(join("\t", $key1, $val1), "\n"); 
     ($key1, $val1) = get($fh1); 
    } 
    elsif ($key1 gt $key2) { 
     print(join("\t", '', '', $key2, $val2), "\n"); 
     ($key2, $val2) = get($fh2); 
    } 
    else { 
     print(join("\t", $key1, $val1, $key2, $val2), "\n"); 
     ($key1, $val1) = get($fh1); 
     ($key2, $val2) = get($fh2); 
    } 
} 

while (defined($key1)) { 
    print(join("\t", $key1, $val1), "\n"); 
    ($key1, $val1) = get($fh1); 
} 

while (defined($key2)) { 
    print(join("\t", '', '', $key1, $val1), "\n"); 
    ($key2, $val2) = get($fh2); 
} 
0

池上が述べたように、それはあなたの例のように、ファイル内容が配置されていることを前提としています。

use strict; 
use warnings; 

open my $file1, '<file1.txt' or die $!; 
open my $file2, '<file2.txt' or die $!; 

my $file1_line = <$file1>; 
print $file1_line; 

while (my $file2_line = <$file2>) { 
    if(defined($file1_line = <$file1>)) { 
     chomp $file1_line; 
     print $file1_line; 
    } 

    my $tabs = $file1_line ? "\t" : "\t\t"; 
    print "$tabs$file2_line"; 
} 

close $file1; 
close $file2; 

例を確認すると、両方のファイルにいくつかの同一のキーと値のペアが表示されます。これを考えると、ファイル1に固有のペアをファイル2に固有のものとして表示し、共通のペアを表示するように見えます。これが事実である(そして、あなたがキーまたは値のいずれかによってファイルペアを一致しようとしていない)場合はuse List::Compare:

use strict; 
use warnings; 
use List::Compare; 

open my $file1, '<file1.txt' or die $!; 
my @file1 = <$file1>; 
close $file1; 

open my $file2, '<file2.txt' or die $!; 
my @file2 = <$file2>; 
close $file2; 

my $lc = List::Compare->new(\@file1, \@file2); 

my @file1Only = $lc->get_Lonly; # L(eft array)only 
for(@file1Only) { print } 

my @bothFiles = $lc->get_intersection; 
for(@bothFiles) { chomp; print "$_\t$_\n" } 

my @file2Only = $lc->get_Ronly; # R(ight array)only 
for(@file2Only) { print "\t\t$_" } 
1

そのわずかなデータ構造を作る程度ならば、あなたは、これは非常に簡単にすることができますすることができます。

#!/usr/bin/env perl 

# usage: script.pl file1 file2 ... 

use strict; 
use warnings; 

my %data; 
while (<>) { 
    chomp; 
    my ($key, $value) = split; 
    push @{$data{$key}}, $value; 
} 

use Data::Dumper; 
print Dumper \%data; 

任意の形式で出力できます。実際にファイルを正確に使用しているのであれば、それはやや難解です。

ジョエル・ベルガーの答えと同様に
0

が、このアプローチは、あなたにできますが、ファイルがなかったか、指定したキーが含まれていなかったかどうかを追跡:

my %data; 

while (my $line = <>){ 
    chomp $line; 
    my ($k)   = $line =~ /^(\S+)/; 
    $data{$k}{line} = $line; 
    $data{$k}{$ARGV} = 1; 
} 

use Data::Dumper; 
print Dumper(\%data); 

出力:

$VAR1 = { 
    'CCC' => { 
    'other.dat' => 1, 
    'data.dat' => 1, 
    'line' => 'CCC 333' 
    }, 
    'BBB' => { 
    'other.dat' => 1, 
    'data.dat' => 1, 
    'line' => 'BBB 345' 
    }, 
    'DDD' => { 
    'other.dat' => 1, 
    'line' => 'DDD 444' 
    }, 
    'AAA' => { 
    'data.dat' => 1, 
    'line' => 'AAA 123' 
    } 
}; 
関連する問題