4

私は2つのテキストファイルを持っています。file1ID のリストが含まれています。

11002
10995
48981
79600

file2:

10993   item    0
11002   item    6
10995   item    7
79600   item    7
439481  item    5
272557  item    7
224325  item    7
84156   item    6
572546  item    7
693661  item    7
.....

file2ID (最初の列) がある場所からすべての行を選択しようとしていますfile1。現在、私がやっていることは、最初のファイルをループして次のような正規表現を作成することです:

^\b11002\b\|^\b10995\b\|^\b48981\b|^\b79600\b

次に実行します。

grep '^11002\|^10995\|^48981|^79600' file2.txt

しかし、ID の数file1が多すぎる (~2000) と、正規表現は非常に長くgrepなり、遅くなります。別の方法はありますか?Perl + Awk + ​​Unix を使用しています。

4

7 に答える 7

6

ハッシュテーブルを使用します。メモリを大量に消費する可能性がありますが、ルックアップは一定時間で行われます。file1これは、ハッシュテーブルを作成し、キーとして使用し、ハッシュテーブルでキーを検索するための、効率的で正しい手順です。これは1つだけではなく、効率的で正しい手順file2です。キーがハッシュテーブルにある場合、その行は標準出力に出力されます。

#!/usr/bin/env perl

use strict;
use warnings;

open FILE1, "< file1" or die "could not open file1\n";
my $keyRef;
while (<FILE1>) {
   chomp;
   $keyRef->{$_} = 1;
}
close FILE1;

open FILE2, "< file2" or die "could not open file2\n";
while (<FILE2>) {
    chomp;
    my ($testKey, $label, $count) = split("\t", $_);
    if (defined $keyRef->{$testKey}) {
        print STDOUT "$_\n";
    }
}
close FILE2;

Perlで同じことをする方法はたくさんあります。とは言うものの、Perlスクリプトに戻って変更を加える必要があるのはいつかわからず、そのままでは管理が難しいため、私は派手な曖昧さよりも明確さと明確さを重視しています。一人の意見。

于 2012-12-05T21:03:19.993 に答える
4
awk 'NR==FNR{tgts[$1]; next} $1 in tgts' file1 file2

見て:

$ cat file1
11002
10995
48981
79600
$ cat file2
10993   item    0
11002   item    6
10995   item    7
79600   item    7
439481  item    5
272557  item    7
224325  item    7
84156   item    6
572546  item    7
693661  item    7
$ awk 'NR==FNR{tgts[$1]; next} $1 in tgts' file1 file2
11002   item    6
10995   item    7
79600   item    7
于 2012-12-05T21:13:29.743 に答える
3

そのために設計されたツールを使用することをお勧めします。結合コマンドを使用します。詳細については、「man join」を実行してください。

linux_prompt> join file1 file2
11002 item 6
10995 item 7
79600 item 7
于 2012-12-05T21:38:17.587 に答える
2

使用grep

$ grep -f f1 f2
11002   item    6
10995   item    7
79600   item    7

注:複数のシステムで提案された回答の多くをテストしましたが、最後の一致のみを表示するものもあります79600 item 7!?

于 2012-12-05T20:59:54.977 に答える
1

最初のファイルのすべての要素をハッシュにロードします。2番目のファイルの各行について^(\d*) 、ハッシュに抽出された番号が含まれている場合は、正規表現を使用して番号を抽出し、それを印刷します

于 2012-12-05T21:04:53.837 に答える
0

Perl の簡単な解決策は、ハッシュを使用して、求められた数字の出現回数をカウントすることです。

perl -lanwe 'print if $a{$F[0]}++ == 1;' file1.txt file2.txt

サンプルデータから次の出力が得られます。

11002   item    6
10995   item    7
79600   item    7

コマンドラインでは正しい順序でファイルを使用する必要があることに注意してください。

これは、入力ファイル名 ( -n) を開いて読み取り、行 ( -a) をに自動分割し@F、その番号のハッシュの値が 1 に等しい場合、各行を出力します。file2 から複数の値を出力したい場合は、単純にに変更== 1>= 1ます。

++等価比較が行われた後に演算子が適用されることに注意してください。

于 2012-12-05T22:50:20.757 に答える
0

プロセス置換を使用して、file1 の ID を正規表現に変換します。

grep -f <(sed 's/.*/^&\\b/' file1) file2

あなたがbashまたは同様の機能を備えたシェルを使用していると仮定しています

于 2012-12-05T22:07:38.063 に答える