ファイル内の各行を他のすべての行と費用効果的に関連付ける

ファイル内の各行を他のすべての行と費用効果的に関連付ける

数字のみを含む非常に大きなファイルがあります。ドキュメント -

123212
234234
12324
1243223
5453443

各行を他のすべての行とペアリングしたいと思います。出力は次のとおりです

123212,234234
123212,12324
123212,1243223
123212,5453443
234234,123212
234234,12324
234234,1243223
234234,5453443
12324,123212
12324,234234
12324,1243223
12324,5453443
1243223,123212
1243223,234234
1243223,12324
1243223,5453443
5453443,123212
5453443,234234
5453443,12324
5453443,1243223

これは、入力ファイルに50L以上のレコードが含まれているためです。したがって、ループを介してこれを行うと、高価な作業になります。

答え1

この出力を生成するすべての方法は高価です。ただし、このアプローチはファイルがRAMよりはるかに大きい場合でも機能します。

$ while read n; do awk -v n="$n" '$1!=n{print n "," $1}' file; done <file
123212,234234
123212,12324
123212,1243223
123212,5453443
234234,123212
234234,12324
234234,1243223
234234,5453443
12324,123212
12324,234234
12324,1243223
12324,5453443
1243223,123212
1243223,234234
1243223,12324
1243223,5453443
5453443,123212
5453443,234234
5453443,12324
5453443,1243223

複数行に書き込む

while read n
do
    awk -v n="$n" '$1!=n{print n "," $1}' file
done <file

read nfile一度に1つの数字を読んでください。それぞれに対して awk スクリプトを実行して、最初の列に出力セクションを作成しますnnこのオプションは、シェル変数と同じ値で名前付き-v n="$n"awk変数を生成します。この条件は、ファイル内のこの行と番号の異なる行を選択します。この行の場合は、番号、カンマ、行番号を順番に印刷します。nn$1!=nfilenn

答え2

私はジョンのコメントに同意します。何があっても費用がかかります。

join -o 1.2,1.3,2.2,2.3 -j 1 <(awk '{printf "%s %d %s\n", "x", FNR, $0}' file) \
<(awk '{printf "%s %d %s\n", "x", FNR, $0}' file) |
awk '$1 != $3{print $2, $4}'

それぞれを使用して2つのプロセス代替インスタンスを起動しawk、ファイルの内容を返し、各レコードの先頭に2つの合成フィールドを挿入できます。最初のフィールドには固定値(x上記の例では)が含まれ、2番目のフィールドには行番号が含まれています。その後、これはjoin結合フィールドとして指定されたフィールド1に供給できます。これにより、プロセスは、2番目のインスタンスのすべてのレコードと一致する最初のインスタンスのすべてのレコードを置き換えます。後処理装置を使用して、awk独自に一致するレコードインスタンスを削除します(この場合、行番号が同じであるという事実を利用します)。

答え3

まったく異なるアプリケーションの使用を考えてみますか?KDB+

(32ビット版は無料です -ビールのようにメモリ制限は4GBです)

いくつかの基本事項:

  1. ファイルを単一の列数値のリストとしてロードします。

    flip (enlist "I";",") 0: hsym `$"/path/to/input"
    
    • 0:入力ファイルからロードされた汎用関数。この質問の目的に応じて、(enlist "I";",")単にファイル形式の仕様として考えて適用します。flip出力を使用可能なリストに変換します。
  2. アプリケーションcross機能。

    a cross a:... <from above>
    
    • q(kdb +の言語)は非常に簡潔であるかもしれませんが、変数の割り当て(たとえば、にa:42設定)を順番に割り当てて使用できることを意味します。ここでは、直接実行できるようにファイル入力を変数に割り当てます。42aacross
  3. 文字列出力を準備します。

    "," 0: flip a... <from above>
    
    • 0:結果をカンマ区切り文字列として準備するために再利用されます。
  4. 出力ファイルに書き込みます。

    (hsym `$"/path/to/output") 0: ","... <from above>
    
    • 今回は、関数の使い方を明確にするために()左側のパラメータを囲む必要があります。最後にここに0:hsym0:第三ファイルが作成された時間。

一緒に入れてください:

(hsym`$"/path/to/output")0:","0:flip a cross a:flip(enlist"I";",")0:hsym`$"/path/to/input"

今悪いニュースがあります…

32ビットフリーバージョンの4GB RAM制限は、約32ビットしか処理できません。6000ジュール...

q)\ts (hsym`$"output6k.txt")0:","0:flip a cross a:flip(enlist"I";",")0:hsym`$"test6k.txt"
23428 3378126736
q)count distinct flip (enlist "I";",") 0:hsym`$"test6k.txt"
6000

\tsディスプレイは24秒もかからず、ほぼ3.4GBのメモリを占有します。

とにかく私の努力を無駄にしないために、これを答えとして投稿することにしました...)

答え4

各行を互いに結合するSQLiteデータベースを作成します。

sqlite3 tmp.db
sqlite> CREATE TABLE T (x INTEGER);
sqlite> .import input_file T
sqlite> .mode csv
sqlite> .output output_file
sqlite> SELECT * FROM T JOIN T AS S WHERE T.x != S.x;

このソリューションは入力ラインの順序を保証しませんが、プロセスを開始するだけで外部ループがなく、限られたRAMで動作する必要があります。

修正する: 値を独自に関連付けないように select 文を変更します。同じ行にない限り、同じ値が正しい場合は使用してくださいWHERE T.rowid != S.rowid

関連情報