텍스트 파일에서 중복 줄을 제거하는 방법? 것은 원래 순서를

내 거대한 (최대 2 GiB) 텍스트 파일에는 모든 줄의 약 100 정확한 사본이 포함되어 있습니다 (제 경우에는 CSV와 같은 데이터 테이블이므로 쓸모가 없습니다).

내가 필요로하는 것은 원래 순서를 유지하면서 모든 반복을 제거하는 것이 좋습니다 (바람직하게는 성능을 크게 향상시키기 위해 희생 될 수 있음). 결과적으로 각 라인은 고유해야합니다. 100 개의 동일한 행이있는 경우 (일반적으로 복제본이 파일에 분산되고 이웃이 아님) 남은 종류 중 하나만 있어야합니다.

이것을 구현하기 위해 스칼라로 프로그램을 작성했습니다 (스칼라에 대해 모른다면 Java로 간주하십시오). 그러나 더 빠른 C 작성 네이티브 도구가 더 빠를 수 있습니까?

업데이트 : awk '!seen[$0]++' filename파일이 2 GiB 이하인 경우 솔루션이 제대로 작동하는 것처럼 보였지만 이제는 8 GiB 파일을 정리할 때 더 이상 작동하지 않습니다. 4GiB RAM이 장착 된 Mac과 4GiB RAM이 장착 된 64 비트 Windows 7 PC 및 6GiB 스왑에서 메모리가 부족한 것으로 보입니다. 그리고 나는이 경험을 감안할 때 4GiB RAM을 가진 리눅스에서 시도하는 것에 대해 열의를 느끼지 않습니다.



답변

awk#bash (Freenode의)에 본 솔루션 :

awk '!seen[$0]++' filename

답변

표준 유틸리티를 사용하는 간단한 (명백한 것은 아닙니다) 방법은 run 이외의 대용량 메모리가 필요하지 않습니다 sort. 대부분의 구현에서는 대용량 파일에 대한 특정 최적화 (좋은 외부 정렬 알고리즘)가 있습니다. 이 방법의 장점은 특수 목적 유틸리티 내부의 모든 행을 반복하며 해석되는 언어는 사용하지 않는 것입니다.

<input nl -b a -s : |           # number the lines
sort -t : -k 2 -u |             # sort and uniquify ignoring the line numbers
sort -t : -k 1n |               # sort according to the line numbers
cut -d : -f 2- >output          # remove the line numbers

모든 행이 공백이 아닌 문자로 시작하면 다음 옵션 중 일부를 생략 할 수 있습니다.

<input nl | sort -k 2 -u | sort -k 1n | cut -f 2- >output

대량의 복제의 경우 메모리에 각 줄의 단일 사본 만 저장하면되는 방법이 더 좋습니다. 약간의 해석 오버 헤드가 있기 때문에 매우 간결한 awk 스크립트가 있습니다 (이미 enzotib 게시 ).

<input awk '!seen[$0]++'

덜 간결하게 : !seen[$0] {print} {seen[$0] += 1}즉, 현재 행이 아직 보이지 않으면 인쇄 seen하고이 행 의 카운터를 증가시킵니다 (초기화되지 않은 변수 또는 배열 요소는 숫자 값 0).

긴 줄의 경우 각 줄의 스푸핑 불가능한 체크섬 (예 : 암호화 요약) 만 유지하여 메모리를 절약 할 수 있습니다. 예를 들어 SHA-1을 사용하면 라인 당 20 바이트에 일정한 오버 헤드가 필요합니다. 그러나 컴퓨팅 다이제스트는 다소 느립니다. 이 방법은 빠른 CPU (특히 다이제스트를 계산하는 하드웨어 가속기가있는 CPU)가 있고 파일 크기와 충분한 긴 줄에 비해 많은 메모리가없는 경우에만 유효합니다. 기본 유틸리티는 각 라인에 대한 체크섬을 계산할 수 없습니다. Perl / Python / Ruby /…의 해석 오버 헤드를 부담하거나 전용 컴파일 된 프로그램을 작성해야합니다.

<input perl -MDigest::MD5 -ne '$seen{Digest::MD5::md5($_)}++ or print' >output

답변

sort -u big-csv-file.csv > duplicates-removed.csv

출력 파일이 정렬됩니다.


답변

중복 제거 된 파일을 메모리에 충분히 저장할 수 있다고 가정하면 (데이터가 실제로 100 배로 복제 된 경우 약 20MiB + 오버 헤드 여야 함) Perl을 사용하면이 작업을 매우 쉽게 수행 할 수 있습니다.

$ perl -ne 'print unless $dup{$_}++;' input_file > output_file

이것은 순서도 유지합니다.

원하는 %dup경우 해시 에서 각 라인의 발생 횟수를 추가 된 무료 보너스로 추출 할 수 있습니다.

원하는 awk경우이 작업도 수행해야합니다 (perl 버전과 동일한 논리, 동일한 순서, dup변수에 수집 된 동일한 데이터 ).

$ awk '{if (++dup[$0] == 1) print $0;}' input_file > output_file

답변

적절한 지원을 제공하는 다른 답변이 없으므로 다음은 하나입니다.

gawk -i inplace '!a[$0]++' file

답변

http://www.computerhope.com/unix/uuniq.htm 을 사용할 수 있습니다uniq

uniq 파일에서 반복되는 행을보고하거나 필터링합니다.


답변

파이썬 원 라이너 :

python -c "import sys; lines = sys.stdin.readlines(); print ''.join(sorted(set(lines)))" < InputFile