두 파일에서 줄의 교차점 찾기

두 파일에서 줄의 교차점 찾기

두 개의 파일(단일 열)이 있는 경우 하나는 다음과 같습니다(파일 1)

34
67
89
92
102
180
blue2
3454

두 번째 파일(file2)

23
56
67
69
102
200

두 파일에 공통된 요소(교차점)를 찾는 방법은 무엇입니까? 이 예에서 예상되는 출력은 다음과 같습니다.

67
102

파일마다 항목 수(행 수)가 다르므로 주의하세요. 숫자와 문자열이 혼합될 수 있습니다. 반드시 정렬되지는 않을 수도 있습니다. 각 항목은 한 번만 나타납니다.

고쳐 쓰다:

시간 확인아래의 몇 가지 답변을 바탕으로 합니다.

# generate some data
>shuf -n2000000 -i1-2352452 > file1
>shuf -n2000000 -i1-2352452 > file2

#@ilkkachu
>time (join <(sort "file1") <(sort "file2") > out1)
real    0m15.391s
user    0m14.896s
sys     0m0.205s

>head out1
1
10
100
1000
1000001

#@Hauke
>time (grep -Fxf "file1" "file2" > out2)
real    0m7.652s
user    0m7.131s
sys     0m0.316s

>head out2
1047867
872652
1370463
189072
1807745

#@Roman
>time (comm -12 <(sort "file1") <(sort "file2") > out3)
real    0m13.533s
user    0m13.140s
sys     0m0.195s

>head out3
1
10
100
1000
1000001

#@ilkkachu
>time (awk 'NR==FNR { lines[$0]=1; next } $0 in lines' "file1" "file2" > out4)
real    0m4.587s
user    0m4.262s
sys     0m0.195s

>head out4
1047867
872652
1370463
189072
1807745

#@Cyrus   
>time (sort file1 file2 | uniq -d > out8)
real    0m16.106s
user    0m15.629s
sys     0m0.225s

>head out8
1
10
100
1000
1000001


#@Sundeep
>time (awk 'BEGIN{while( (getline k < "file1")>0 ){a[k]}} $0 in a' file2 > out5)
real    0m4.213s
user    0m3.936s
sys     0m0.179s

>head out5
1047867
872652
1370463
189072
1807745

#@Sundeep
>time (perl -ne 'BEGIN{ $h{$_}=1 while <STDIN> } print if $h{$_}' <file1 file2 > out6)
real    0m3.467s
user    0m3.180s
sys     0m0.175s

>head out6
1047867
872652
1370463
189072
1807745

Perl 버전이 가장 빠르며 그 다음은 awk입니다. 모든 출력 파일의 행 수는 동일합니다.

비교를 위해 출력이 동일하도록 출력을 숫자순으로 정렬했습니다.

#@ilkkachu
>time (join <(sort "file1") <(sort "file2") | sort -k1n > out1)
real    0m17.953s
user    0m5.306s
sys     0m0.138s

#@Hauke
>time (grep -Fxf "file1" "file2" | sort -k1n > out2)
real    0m12.477s
user    0m11.725s
sys     0m0.419s

#@Roman
>time (comm -12 <(sort "file1") <(sort "file2") | sort -k1n > out3)
real    0m16.273s
user    0m3.572s
sys     0m0.102s

#@ilkkachu
>time (awk 'NR==FNR { lines[$0]=1; next } $0 in lines' "file1" "file2" | sort -k1n > out4)
real    0m8.732s
user    0m8.320s
sys     0m0.261s

#@Cyrus   
>time (sort file1 file2 | uniq -d > out8)
real    0m19.382s
user    0m18.726s
sys     0m0.295s

#@Sundeep
>time (awk 'BEGIN{while( (getline k < "file1")>0 ){a[k]}} $0 in a' file2 | sort -k1n > out5)
real    0m8.758s
user    0m8.315s
sys     0m0.255s

#@Sundeep
>time (perl -ne 'BEGIN{ $h{$_}=1 while <STDIN> } print if $h{$_}' <file1 file2 | sort -k1n > out6)
real    0m7.732s
user    0m7.300s
sys     0m0.310s

>head out1
1
2
3
4
5

이제 모든 출력이 동일합니다.

답변1

단순한comm+sort해결책:

comm -12 <(sort file1) <(sort file2)
  • -12- 공통 행(두 파일 모두에서 발생)만 출력되도록 열 1합계(및 각각 고유 행 )를 억제합니다.2FILE1FILE2

답변2

에서는 awk첫 번째 파일을 메모리에 완전히 로드합니다.

$ awk 'NR==FNR { lines[$0]=1; next } $0 in lines' file1 file2 
67
102

또는 특정 행이 발생하는 횟수를 추적하려는 경우:

$ awk 'NR==FNR { lines[$0] += 1; next } lines[$0] {print; lines[$0] -= 1}' file1 file2

join이 작업을 수행할 수 있지만 입력 파일을 정렬해야 하므로 먼저 정렬해야 하며 그렇게 하면 원래 순서가 손실됩니다.

$ join <(sort file1) <(sort file2)
102
67

답변3

awk 'NR==FNR { p[NR]=$0; next; }
   { for(val in p) if($0==p[val]) { delete p[val]; print; } }' file1 file2

이는 (대형 파일의 경우) 동일한 항목을 여러 번 인쇄하고 일치 후 항목을 다시 확인하는 것을 생략하므로 가장 빠르기 때문에 좋은 솔루션입니다.

grep

grep -Fxf file1 file2

동일한 항목이 에 여러 번 나타나면 여러 번 출력됩니다 file2.

유형

재미삼아 (보다 훨씬 느려야 함 grep):

sort -u file1 >t1
sort -u file2 >t2
sort t1 t2 | uniq -d

답변4

약간 다르고 awk동등한 perl버전

3회 연속으로 보고서를 실행하는 데 걸리는 시간

$ # just realized shuf -n2000000 -i1-2352452 can be used too ;)
$ shuf -i1-2352452 | head -n2000000 > f1
$ shuf -i1-2352452 | head -n2000000 > f2

$ time awk 'NR==FNR{a[$1]; next} $0 in a' f1 f2 > t1
real    0m3.322s
real    0m3.094s
real    0m3.029s

$ time awk 'BEGIN{while( (getline k < "f1")>0 ){a[k]}} $0 in a' f2 > t2
real    0m2.731s
real    0m2.777s
real    0m2.801s

$ time perl -ne 'BEGIN{ $h{$_}=1 while <STDIN> } print if $h{$_}' <f1 f2 > t3
real    0m2.643s
real    0m2.690s
real    0m2.630s

$ diff -s t1 t2
Files t1 and t2 are identical
$ diff -s t1 t3
Files t1 and t3 are identical

$ du -h f1 f2 t1
15M f1
15M f2
13M t1

관련 정보