숫자만 포함된 매우 큰 파일이 있습니다. 문서 -
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 n
file
한 번에 하나의 숫자를 읽으십시오. 각각에 대해 awk 스크립트를 실행하여 첫 번째 열에 출력 섹션을 만듭니다 n
. n
이 옵션은 쉘 변수와 동일한 값으로 -v n="$n"
명명된 awk 변수를 생성합니다 . 이 조건은 파일에서 이 줄과 번호가 다른 줄을 선택합니다 . 이 줄의 경우 number , 쉼표, 줄 번호를 차례로 인쇄합니다 .n
n
$1!=n
file
n
n
답변2
나는 John의 의견에 동의합니다. 무슨 일이 있어도 비용이 많이 들 것입니다.
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}'
각각 을 사용하여 두 개의 프로세스 대체 인스턴스를 시작 awk
하고 파일의 내용을 반환하고 각 레코드의 시작 부분에 두 개의 합성 필드를 삽입할 수 있습니다. 첫 번째 필드에는 고정 값( x
위 예에서)이 포함되고 두 번째 필드에는 행 번호가 포함됩니다. 그런 다음 이는 join
조인 필드로 규정된 필드 1 에 공급될 수 있습니다 . 이로 인해 프로세스는 두 번째 인스턴스의 모든 레코드와 일치하는 첫 번째 인스턴스의 모든 레코드를 대체합니다. 후처리기를 사용하여 awk
자체적으로 일치하는 레코드 인스턴스를 삭제합니다(이 경우 줄 번호가 동일하다는 사실을 활용).
답변3
완전히 다른 애플리케이션 사용을 고려해 보시겠습니까?KDB+?
(32비트 버전은 무료입니다 -맥주처럼메모리 제한은 4GB입니다)
몇 가지 기본사항:
파일을 단일 열 숫자 목록으로 로드합니다.
flip (enlist "I";",") 0: hsym `$"/path/to/input"
애플리케이션
cross
기능.a cross a:... <from above>
q
(kdb+의 언어)은 매우 간결할 수 있지만 변수 할당(예: 로a:42
설정 )을 순서대로 할당하고 사용할 수 있음을 의미하기도 합니다. 여기서는 직접 수행할 수 있도록 파일 입력을 변수에 할당합니다 .42
a
a
cross
문자열 출력을 준비합니다.
"," 0: flip a... <from above>
0:
결과를 쉼표로 구분된 문자열로 준비하는 데 다시 사용됩니다.
출력 파일에 씁니다.
(hsym `$"/path/to/output") 0: ","... <from above>
- 이번에는 함수 사용법을 명확하게 하기 위해
()
왼쪽 매개변수를 둘러싸 야 합니다 . 마지막으로 여기에0:
hsym
0:
제삼파일이 작성된 시간입니다.
- 이번에는 함수 사용법을 명확하게 하기 위해
함께 넣어보세요:
(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
.