2

互いに一致するすべての行を見つけたい時系列データがありますが、値は異なる場合があります (最初のタブまで一致します)。他の時系列でのみ発生する日を削除したい場合は、下の vimdiff を参照してください。

これを行うための最も簡単な UNIX ツールを探しています。

ここに画像の説明を入力

ここに画像の説明を入力

ここここで時系列。

簡単な例

入力

Left file                            Right File    
------------------------             ------------------------
10-Apr-00     00:00    0     ||      10-Apr-00     00:00     7
20-Apr 00     00:00    7     ||      21-Apr-00     00:00     3

出力

Left file                           Right File    
------------------------            ------------------------
10-Apr-00     00:00    0    ||      10-Apr-00     00:00     7
4

3 に答える 3

2

比較的知られていない UNIX コマンドjoin があります。キー列でソートされたファイルを結合できます。

コンテキストで使用するには、次の戦略に従います (left.txt と right.txt はファイルです)。

  1. 行番号を追加します(最後のステップで元のシーケンスにすべてを入れるため)

    nl left.txt > left_with_lns.txt
    nl right.txt > right_with_lns.txt
    
  2. 日付列で両方のファイルを並べ替える

    sort left_with_lns.txt -k 2 > sl.txt
    sort right_with_lns.txt -k 2 > sr.txt
    
  3. 日付列 (すべての時間は 0:00) を使用してファイルを結合します (これにより、両方のファイルのすべての列が対応するキーとマージされますが、最初のファイルの列をどこかに書き込み、2 番目のファイルの列を書き込むための出力テンプレートが用意されています別の場所 (ただし、一致するキーを持つ行のみが結果 fl.txt および fr.txt で終了します)

    join -j 2 -t $'\t' -o 1.1 1.2 1.3 1.4 sl.txt sr.txt > fl.txt
    join -j 2 -t $'\t' -o 2.1 2.2 2.3 2.4 sl.txt sr.txt > fr.txt
    
  4. 行番号列で両方の結果をソートし、他の列を出力します

    sort -n fl |cut -f 2- > left_filtered.txt
    sort -n fr.txt | cut -f 2- > right_filtered.txt
    

使用ツール: カット、結合、nl、ソート。

于 2015-11-07T20:11:39.797 に答える
1

@Masi のリクエストに応じて、sed を使用して解決策を見つけようとしました。

私の最初の試みは 2 つのパスを使用します。最初file1は sed スクリプトに変換され、2 番目のパスで filter に使用されますfile2

sed 's/\([^ \t]*\).*/\/^\1\t\/p;t/' file1 > sed1
sed -nf sed1 file2 > out2

大きな入力ファイルでは、これは遅くなります。の各行に対してfile2、sed は の行数に等しい量のパターンを処理する必要がありますfile1。私はプロファイリングを行っていませんが、時間の計算量が 2 次であっても驚かないでしょう。

2 回目の試行では、2 つのファイルをマージして並べ替え、すべての行をスキャンしてペアを探します。これは線形時間で実行されるため、はるかに高速です。この解決策は、ファイルの元の順序を台無しにすることに注意してください。この日付表記では、アルファベット順の並べ替えがうまく機能しません。これを修正する最も簡単な方法は、異なる日付形式 (ymd) のファイルを提供することです。

sed 's/^[^ \t]\+/&@1/' file1 > marked1
sed 's/^[^ \t]\+/&@2/' file2 > marked2

sort marked1 marked2 > sorted

sed '$d;N;/^\([^ \t]\+\)@1.*\n\1@2/{s/\(.*\)\n\(.*\)/\2\n\1/;P};D' sorted > filtered
sed 's/^\([^ \t]\+\)@2/\1/' filtered > out2

説明:

  • 最初のコマンドで、すべての日付にs/^[^ \t]\+/&@1/追加@1します。これにより、ファイルをマージしたり、並べ替え時に同じ日付を保持したり、異なるファイルの行を区別したりできます。
  • 2 番目のコマンドはfile2;に対して同じことを行います。明らかに独自のマーカーを使用します@2
  • このsortコマンドは、2 つのファイルをマージして、同じ日付をグループ化します。
  • 3 番目の sed コマンドはfile2、 にも含まれる日付を持つからのすべての行を返しますfile1
  • 4 番目の sed コマンドは@2、出力からマーカーを削除します。

3 番目の sed コマンドの詳細:

  • $d最後の行の不適切な印刷を抑制します
  • N別の入力行を読み取り、パターン空間に既に存在する行に追加します
  • /^\([^ \t]\+\)@1.*\n\1@2/異なるファイルに由来するが同じ日付の 2 つの行に一致します
  • {コマンドグループを開始します
  • s/\(.*\)\n\(.*\)/\2\n\1/パターン空間の 2 行を入れ替えます
  • Pパターンスペースの最初の行を印刷します
  • }コマンドグループを終了します
  • Dパターンスペースから最初の行を削除します

悪いニュースは、2 番目のアプローチでさえ、@ John1024 による awk アプローチよりも遅いことです。Sed はマージ ツールとして設計されたことはありません。どちらも awk ではありませんでしたが、awk にはファイル全体を辞書に格納できるという利点があり、@ John1024 のソリューションは非常に高速です。ディクショナリの欠点はメモリ消費です。巨大な入力ファイルでは、私のソリューションが有利になるはずです。

于 2015-11-07T01:19:10.743 に答える