我有一个巨大的csv文件,大约有10 ^ 9行,每行有一对id,如:
IDa,IDb
IDb,IDa
IDc,IDd
调用此文件1。我有另一个小得多的csv文件,大约有10 ^ 6行,格式相同。调用此文件2。
我想简单地找到file2中的行,这些行至少包含一个存在于file1中的ID。
有快速的方法吗?如果它是在awk,python或perl中,我不介意。
答案 0 :(得分:5)
$ cat > file2 # make test file2
IDb,IDa
$ awk -F, 'NR==FNR{a[$1];a[$2];next} ($1 in a&&++a[$1]==1){print $1} ($2 in a&&++a[$2]==1){print $2}' file2 file1 > file3
$ cat file3 # file2 ids in file1 put to file3
IDa
IDb
$ awk -F, 'NR==FNR{a[$1];next} ($1 in a)||($2 in a){print $0}' file3 file2
IDb,IDa
答案 1 :(得分:4)
我实际上会使用sqlite
来做类似的事情。您可以使用sqlite3 test.sqlite
从两个文件创建一个新数据库,然后执行类似的操作:
create table file1(id1, id2);
create table file2(id1, id2);
.separator ","
.import file1.csv file1
.import file2.csv file2
WITH all_ids AS (
SELECT id1 FROM file1 UNION SELECT id2 FROM file1
)
SELECT * FROM file2 WHERE id1 IN all_ids OR id2 IN all_ids;
使用sqlite
的优点是,您可以比使用某种脚本语言编写的简单脚本更智能地管理内存。
答案 2 :(得分:2)
使用这些输入文件进行测试:
$ cat file1
IDa,IDb
IDb,IDa
IDc,IDd
$ cat file2
IDd,IDw
IDx,IDc
IDy,IDz
如果file1可以适合内存:
$ awk -F, 'NR==FNR{a[$1];a[$2];next} ($1 in a) || ($2 in a)' file1 file2
IDd,IDw
IDx,IDc
如果没有,但file2可以适合内存:
$ awk -F, '
ARGIND==2 {
if ($1 in inBothFiles) {
inBothFiles[$1] = 1
}
if ($2 in inBothFiles) {
inBothFiles[$2] = 1
}
next
}
ARGIND==1 {
inBothFiles[$1] = 0
inBothFiles[$2] = 0
next
}
ARGIND==3 {
if (inBothFiles[$1] || inBothFiles[$2]) {
print
}
}
' file2 file1 file2
IDd,IDw
IDx,IDc
以上使用GNU awk进行ARGIND - 其他awks只是在开始时添加FNR==1{ARGIND++}
块。
我有ARGIND==2
块(即处理第二个参数的部分,在本例中是10 ^ 9 file1
)首先列出效率,因此我们不会不必要地测试{ {1}}用于更大文件中的每一行。
答案 3 :(得分:1)
在perl中,
use strict;
use warnings;
use autodie;
# read file2
open my $file2, '<', 'file2';
chomp( my @file2 = <$file2> );
close $file2;
# record file2 line numbers each id is found on
my %id;
for my $line_number (0..$#file2) {
for my $id ( split /,/, $file2[$line_number] ) {
push @{ $id{$id} }, $line_number;
}
}
# look for those ids in file1
my @use_line;
open my $file1, '<', 'file1';
while ( my $line = <$file1> ) {
chomp $line;
for my $id ( split /,/, $line ) {
if ( exists $id{$id} ) {
@use_line[ @{ $id{$id} } ] = @{ $id{$id} };
}
}
}
close $file1;
# print lines whose ids were found
print "$_\n" for @file2[ grep defined, @use_line ];
答案 4 :(得分:0)
示例文件:
cat f1
IDa,IDb
IDb,IDa
IDc,IDd
cat f2
IDt,IDy
IDb,IDj
Awk解决方案:
awk -F, 'NR==FNR {a[$1]=$1;b[$2]=$2;next} ($1 in a)||($2 in b)' f1 f2
IDb,IDj
这将在数组a和b中存储file1的第一列和第二列。如果第二个文件中显示第一列或第二列,则打印这些行。