使用脚本过滤文本文件

时间:2011-06-20 15:04:16

标签: python perl

我有一个非常大的制表符分隔的文本文件。某些行在文件中具有相同的值,某些行只具有唯一值,例如:

a   foo
a   bar
a   foo2
b   bar2
c   bar2
c   foo3
d   bar3
...

我还有另一个ID列表文件,它只是整个列表的一部分。例如:

a
b
d
...

我想获取这些ID列表的对应值,ID列表是唯一的。我怎么能用perl脚本或python或basic bash命令呢?欣赏它!

5 个答案:

答案 0 :(得分:1)

Quickie未经测试的Python:

ids = set()
with open('id-list.txt') as f:
    for line in f:
        ids.add(line.strip())
with open('data.txt') as f:
    for line in f:
        parts = line.strip().split('\t', 1)
        if parts[0] in ids:
            print line,

答案 1 :(得分:1)

您还可以使用以下代码(确保它应该被重写(不创建列表和字典,但只是对找到的项目执行某些操作)通常的方式,特别是在您的文件太大时):

ids = [row.strip() for row in open('c:\\ids.txt','r') if row.strip()]
data = dict(row.strip().split() for row in open('c:\\data.txt','r') if row.strip())
for id in ids:
    print data.get(id)

很抱歉,错过了ID可能有多个值:

output = {}
for row in open('c:\\tst.txt','r'):
    if not row.strip():
        continue
    id, datavalue = row.strip().split()
    if not id in output:
        output[id] = []
    output[id].append(datavalue)

或使用defaultdict

from collections import defaultdict

output = defaultdict(list)
for row in open('c:\\tst.txt','r'):
    if not row.strip():
        continue
    id, datavalue = row.strip().split()
    output[id].append(datavalue)

答案 2 :(得分:1)

在perl:

use strict;
use warnings;
use autodie;

open my $id_list, '<', 'id_list_file';
my %ids = map { chomp; $_ => 1 } readline $id_list;
close $id_list;

open my $text_file, '<', 'text_file';
while ( my $line = readline $text_file ) {
    chomp $line;
    my ($id, $value) = split /\t/, $line, 2;
    if ( $ids{ $id } ) {
        print "got value $value for id $id\n";
    }
}

答案 3 :(得分:1)

快速查看 ID 列表:

a foo
a bar
a foo2
b bar2
c bar2
c foo3
d bar3

似乎a可以是foobar。第二列是唯一的,但不是第一列。但是,您的其他列表如下所示:

a
b
d

这似乎说第一列(不是唯一的)是键。当我在第一个列表中阅读a时,我应该返回什么。我是否同时返回foobar,或者这是一个错误?

在我们给你答案之前,我需要知道这一点。


附录

  

我需要归还他们两个。对此感到抱歉

好的,在Perl中,存储关键信息的最简单方法是使用 Hash 。哈希的问题在于每个键只有一个值。在您的文件中,情况并非如此,每个键都有两个单独的值。有两种方法可以解决这个问题:

方法#1:将值附加到上一个值

open (ID_FILE, "id_file.txt")
    or die qq(Can't open "id_file.txt" for reading\n);
my %idHash;
while (my $line = <ID_FILE>) {
    chomp $line;
    my ($key, $value) = split("/s+", $line);
    if (exists $idHash{$key}) {
        $idHash{$key} .= " " . $value;
    }
    else {
        $idHash{$key} = $value;
    }
}
close ID_FILE;

在循环结束时,$idHash{'a'} = foo bar。因此,在你的第二个循环中:

open (ID_LIST, 'list_of_ids.txt')
    or die qq(Can't open "list_of_ids.txt" for reading\n);
while (my $line = <ID_LIST>) {
    chomp $line;
    print qq("$line" keys are "$idHash{$line}"\n);
}

方法#2:存储哈希列表

这是危险的领域。它增加了混乱,我通常建议你在进入列表的哈希或哈希等列表时考虑面向对象的编程。

open (ID_FILE, "id_file.txt")
    or die qq(Can't open "id_file.txt" for reading\n);
my %idHash;
while (my $line = <ID_FILE>) {
    chomp $line;
    my ($key, $value) = split("/s+", $line);
    push(@{$idHash{$line}}, $value);
}
close ID_FILE;

@{$idHash{$line}}将哈希值视为对哈希的引用,如果它更清楚,你可以将它分开:

open (ID_FILE, "id_file.txt")
    or die qq(Can't open "id_file.txt" for reading\n);
my %idHash;
while (my $line = <ID_FILE>) {
    chomp $line;
    my ($key, $value) = split("/s+", $line);
    my @tempList = \$idHash{$line};
    push(@tempList, $value);
}
close ID_FILE;

现在,当您进行查找时,您将不得不浏览列表:

open (ID_LIST, 'list_of_ids.txt')
    or die qq(Can't open "list_of_ids.txt" for reading\n);
while (my $line = <ID_LIST>) {
    chomp $line;
    my @tempList = \$idHash{$line};
    print "The values for key $line are " . join(", ", @tempList) . "\n";;
    print "The values for key $line are " . join(", ", @{$idHash{$line}) . "\n"; 
}

或者,您可以解析每个键的列表项,而不是执行join

open (ID_LIST, 'list_of_ids.txt')
    or die qq(Can't open "list_of_ids.txt" for reading\n);
while (my $line = <ID_LIST>) {
    chomp $line;
    foreach my $value (@{$idHash{$line}) {
        print qq(Value: $line" \t key "$value"\n);
    }
}

顺便说一下,我很抱歉,但由于时间不够,我还没有测试过代码。因此,我可以保证有语法错误和错误。但是,它确实为您提供了如何使用Perl Hash通过密钥快速提取值以及如何为单个密钥存储多个值的一般概念。

看起来原始的Python答案遇到了同样的问题。但是,修改后的版本看起来是正确的。

答案 4 :(得分:1)

您可以通过读取第一个文件来创建哈希。将您的id作为键和相应值集的数组作为值。在读取第二个文件时,只需使用第一个文件在您创建的哈希中进行查找。