-2

現在、perl スクリプトで 2 つの異なるテキスト ファイルをマージしようとしていますが、それよりも少し複雑です。

問題(説明を簡単にするために少し変更):

2 つの異なるテキスト ファイルがあり、1 つは名前付きdog1.txtで、もう 1 つは名前付きですdog2.txt(以下を参照)。

dog1.txt
    poodle     8888
    jackrussel    5743
    beagle     6784

dog2.txt 
    spaniel    9843
    poodle    3756
    germanshepard    3267
    beagle    3478  

ご覧のとおり、プードルとビーグルは両方のテキスト ファイルに含まれていますが、それぞれに関連付けられている 4 桁のコードが異なります。

私が欲しいのは、これら2つのファイルをマージして作成された新しいファイルであり、プードルとビーグルなどの重複がある場合、プードルとビーグルに関連付けられた4桁を新しいファイルに含めて、dog1.txtファイルから取得したいdog2.txt の代わりに。

新しいファイルは次のようになります (犬の名前の順序は関係ありません。犬の名前に関連付けられている番号は正しい必要があります)。

final_dog.txt
    poodle    8888
    germanshepard    3267
    jackrussel    5743
    beagle    6784
    spaniel    9843

私は多くのさまざまなソリューションを試しましたが、必要な方法で確実に機能するものはありません。

どんな助けでも大歓迎です、ありがとう

4

3 に答える 3

4

基本的に、最初に遭遇したインスタンスを印刷する必要があります。そのため、重複を削除するための標準的なイディオムを使用できます。

perl -lane'print if !$seen{$F[0]}++' dog1.txt dog2.txt >final_dog.txt

このアプローチは、最小量のメモリを使用します。また、可能な限り早い段階で出力の生成を開始します(出力を配管する場合に便利です)。


新しい要件を満たすには、

perl -lane'print if @F==2 && $F[1]=~/^\d+\z/ && !$seen{$F[0]}++' \
   dog1.txt dog2.txt >final_dog.txt
于 2012-12-04T23:49:56.533 に答える
0

ワンライナーとして:

perl -MData::Dumper -lwe '
           $d = pop;             # save filename for later
           %d = map split, <>;   # process dog1.txt
           push @ARGV, $d;       # put the second file name back
           while (<>) {          # add new entries, unless already defined
               my ($dog,$num) = split; $d{$dog} //= $num; 
           } 
           print Dumper \%d' dog1.txt dog2.txt

出力:

$VAR1 = {
          'poodle' => '8888',
          'spaniel' => '9843',
          'germanshepard' => '3267',
          'beagle' => '6784',
          'jackrussel' => '5743'
        };

@ARGVこのソリューションでは、ひし形演算子によって引数に対して行われる暗黙的なオープンを使用します<>。defined-or 代入演算子は、//=既に定義されている値を上書きしません。

池上が巧みに指摘しているように、引数を逆にすることで、値をチェックする必要がなくなります。次に、これは非常に簡単になります。

perl -MData::Dumper -lwe '
           %d = map split, <>; 
           print Dumper \%d' dog2.txt dog1.txt   # note reversed args

ファイルがタブで区切られているかどうかを指定していないため、printステートメントはあなたに任せます。しかし、あなたは次のようなことをするかもしれません:

print join "\t", $_, $d{$_} for keys %d;      # tab separated
printf "%-20s %s\n", $_, $d{$_} for keys %d;  # fixed width

元の形式を保持する池上の答えとは異なり、これは破壊的な解決策であることに注意してください。

于 2012-12-04T23:44:24.743 に答える
-1

このソリューションは、あなたが要求したことを実行し、さらに、各行の値にスペースが含まれている可能性がある場合にも対応します。

use strict;
use warnings;

my %data;

for my $file (qw/ dog2.txt dog1.txt /) {

  open my $fh, '<', $file or die $!;

  while (<$fh>) {
    $data{$1} = $2 if /(\S+)\s+(\S(?:.*\S)?)/;
  }
}

while (my ($key, $val) = each %data) {
  print "$key $val\n";
}

出力

poodle 8888
spaniel 9843
germanshepard 3267
beagle 6784
jackrussel 5743
于 2012-12-05T01:08:15.937 に答える