質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
bash

bash(Bourne-again-Shell)は sh(Bourne Shell)のインプリメンテーションに様々な機能が追加されたシェルです。LinuxやMac OS XではBashはデフォルトで導入されています。

シェルスクリプト

シェルスクリプトは、UNIX系のOSもしくはコマンドラインインタプリタ向けに記述されたスクリプト。bash/zshといったシェルによって実行されるため、このように呼ばれています。バッチ処理などに使用されており、テキストファイルに書かれた命令を順に実行します。

Perl

Perlは多目的に使用される実用性が高い動的プログラミング言語のひとつです。

Q&A

解決済

2回答

679閲覧

2ファイル間で、カンマ区切りの範囲で一致する行を、除外するには

Mocchan2718

総合スコア15

bash

bash(Bourne-again-Shell)は sh(Bourne Shell)のインプリメンテーションに様々な機能が追加されたシェルです。LinuxやMac OS XではBashはデフォルトで導入されています。

シェルスクリプト

シェルスクリプトは、UNIX系のOSもしくはコマンドラインインタプリタ向けに記述されたスクリプト。bash/zshといったシェルによって実行されるため、このように呼ばれています。バッチ処理などに使用されており、テキストファイルに書かれた命令を順に実行します。

Perl

Perlは多目的に使用される実用性が高い動的プログラミング言語のひとつです。

1グッド

0クリップ

投稿2023/11/25 06:49

編集2023/11/27 04:37

実現したいこと

大元のファイルのカンマ区切りの先頭が、
比較対象のファイル内の行と一致する行を、除外したいです。

▼データのイメージ

大元のファイル:src.txt

10,0 9,0 8,0 7,0 6,0 5,0 4,0 3,0 2,0 1,0

比較対象のファイル:dst.txt

1 2 3 4 5

▼期待される出力結果

src.txtのうち、「5,0」~「1,0」の5行が
除外されたテキストが、出力される。

最終的な出力結果は、ソートされていなくてもOKなものとする。

10,0 6,0 7,0 8,0 9,0

前提

src.txt側が数百万行単位の大規模データとなっても、
実行時間を短縮できるように、なるべくパフォーマンスを重視したいです。

PythonやPHP等のスクリプト言語で、
配列ループ・配列の要素判定をする方式であれば、
比較的容易に実現可能ではありますが、実行速度に難がある状態です。

また、古いシステムでも利用できるように、
可能な限りbashやperl辺りで完結させたいと考えております。

試したこと

commコマンド、cutコマンドを組み合わせるやり方では、
src.txt側に元々入っている付属情報が抜け落ちてしまっています。
(最終的には、,0の部分まで、該当の行全体が出力されるようにしたい)

bash

1$ comm -23 <(sort src.txt | cut -f 1 -d ',') <(sort dst.txt) 210 36 47 58 69

補足情報(FW/ツールのバージョンなど)

  • CentOS 6.6
  • bash 4.1.2
  • perl 5.10.1
  • Python 2.6.6
melian👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

arcxor

2023/11/25 07:11

1 は 10 に部分一致しますがなぜ 10 は残るのでしょうか。部分一致の定義を明確にしてください。
Mocchan2718

2023/11/25 07:22

確かに仰る通りでした。 「部分一致」というよりは、「src.txtをカンマ区切りにした状態の1列目のテキストが、dst.txt側の行に含まれているかどうか?」等の方が適切でした。
guest

回答2

0

パフォーマンスは実行環境にも影響を受けますので、質問者さんの環境で測定してください。

Pythonでも愚直にループを回すのではない方法はあります。集合型を使ってみました。

python

1dst = set() 2with open('dst.txt') as f: 3 for line in f: 4 line = line.strip() 5 if len(line): 6 dst.add(line) 7 8with open('src.txt') as f: 9 for line in f: 10 key, _ = line.split(",", 1) 11 if key in dst: 12 continue 13 print(line, end="")

Python 3.x向けです。Python 2.7で使用するには最終行を "print line," に変更します。

投稿2023/11/25 08:29

編集2023/11/25 22:07
ikedas

総合スコア4400

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Mocchan2718

2023/11/25 08:52

ご回答いただきありがとうございます。 集合型を使う方法は思いつきませんでした。 確かに集合型で判定すれば、愚直にループさせるよりも早くなりそうですね。 動作想定のシステムでは、まだ2系のPythonが動いているため、 仰る通り調整が必要になりそうです。
ikedas

2023/11/25 22:20

Python 2.7はprint文の書式を変えるだけでした。 ところで、「パフォーマンス」を気にしていらっしゃったのに測定はされないのでしょうか。 私の手元では、src.txtが10000行、dst.txtが1000行の場合、次の結果となりました。 python 2.7: real 0m0.039s user 0m0.024s sys 0m0.015s grep: real 0m0.105s user 0m0.076s sys 0m0.030s join: real 0m0.036s user 0m0.028s sys 0m0.014s Pythonとjoin方式とは遜色ないですが、データが100万行オーダーに増えた場合にどちらが速いかは検証が必要でよう。また、メモリ使用量が問題になる可能性もあります。 再度。パフォーマンスは質問者さんの環境で測定してください。
Mocchan2718

2023/11/27 04:36 編集

追加でコメントいただきありがとうございます。 Python 2系でも、print "string", で改行文字無しで文字列を出力できるのですね。 https://www.lifewithpython.com/2013/12/python-print-without-.html src.txtを700万件、dst.txtを5万件の状態で、実行時間の計測も含めて、再度テストしてみました。 私の環境ではPython 2.6.6でしたが、それでもPythonが一番早く終了しました。 古いシステムであっても、コマンド以外の方法も含めて柔軟に考えるのが大事ですね。。 ▼grepの場合 time grep -Ev -f <(sed -E 's/^.+$/^&,/' dst.txt) src.txt > filtered_list.txt real 1m34.214s user 1m28.832s sys 0m3.059s ※filtered_list.txtが336万件強の時点で、強制終了。(恐らくメモリ不足?) ▼joinの場合 time join -v1 -t, <(sort -t, -k1,1 src.txt) <(sort dst.txt) > filtered_list.txt real 0m20.384s user 0m19.427s sys 0m0.273s ▼Pythonの場合 time python filter.py > filtered_list.txt real 0m5.685s user 0m5.423s sys 0m0.135s ※joinの場合・Pythonの場合の共に、除外後のリストの内容が一致していることも確認できました。 diff <(sort <LIST_BY_JOIN>) <(sort <LIST_BY_PYTHON>) ※そして今更ながら、似たような質問が既に出ておりました・・。申し訳ありません。 https://teratail.com/questions/t6o7mwtp092kg0
Mocchan2718

2023/11/27 05:34

もしPythonも入っていない環境で、同様のことを実現したい場合、 awkコマンドを使うという手もありそうです。 今回のケースでは、Pythonを別途インストールして使うのがベストではありますが。 time awk -F, 'FNR==NR{a[$1]++; next} !a[$1]' dst.txt src.txt > filtered_list.txt real 0m7.110s user 0m6.422s sys 0m0.474s awkコマンドの場合は、src.txt側の列数が変わっても、同じ内容で動作するというメリットもあるようです。 (試してみて気づきになったので、コメントに残しておきます)
guest

0

ベストアンサー

「src.txtをカンマ区切りにした状態の1列目のテキストが、dst.txt側の行に含まれているかどうか?」

grep コマンドの場合

bash

1$ grep --version 2grep (GNU grep) 3.11 3 4$ grep -Ev -f <(sed -E 's/^.+$/^&,/' dst.txt) src.txt 510,0 69,0 78,0 87,0 96,0

join コマンドの場合

bash

1$ join --version 2join (GNU coreutils) 9.1 3 4$ join -v1 -t, <(sort -t, -k1,1 src.txt) <(sort dst.txt) 510,0 66,0 77,0 88,0 99,0

投稿2023/11/25 07:21

編集2023/11/25 08:34
melian

総合スコア19883

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Mocchan2718

2023/11/25 08:53

ご回答いただきありがとうございます。 Linuxコマンドのみで完結されている点、 複数の例を提示してくださっている点から、 ベストアンサーとさせていただきました。 src.txtを700万件、dst.txtを5万件に増やして確認してみました。 grepコマンドの場合は、残り5万件ほどのところで 処理が暫く止まってしまいましたが、 joinコマンドの場合は、ものの数秒で処理が完了しておりました。 いずれのやり方も、発想として全く思い浮かばず、勉強になりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問