【问题标题】:filter text file using script使用脚本过滤文本文件
【发布时间】:2011-06-21 02:56:24
【问题描述】:

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

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

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

a
b
d
...

我想得到那些ID列表的对应值,ID列表是唯一的。如何使用 perl 脚本或 python 或基本 bash 命令来执行此操作?欣赏!

【问题讨论】:

  • 看看grep -f

标签: python perl


【解决方案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";
    }
}

【讨论】:

  • 解压后是否需要关闭文件?
  • 你不需要,但为什么不呢?它更清楚地表明您将不会在以后的代码中再次使用它。
  • 当我运行你的脚本时没有任何反应。我是否遗漏了一些论点?
  • 您的地图看起来有点古怪。看来您的散列正在使用整行作为1 值的键,而不是将行拆分为键和值,并创建$ids{$key} = $value。我读错了吗?也许你是对的,我只是感到困惑。我很容易被闪亮的物体弄糊涂和分心。
  • 如图所示的“ID列表文件”只有id,没有id和value。
【解决方案2】:

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,

【讨论】:

    【解决方案3】:

    您也可以使用以下代码(确保它应该被重写(不创建列表和字典,而只是对找到的项目执行一些操作)通常的方式,尤其是在您的文件太大的情况下):

    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)
    

    【讨论】:

    • 为什么只能使用id列表打印一个数据。我还想打印具有相同 ID 的所有结果。
    • @Jianguo - use 'ids = [row.strip() for row in open('c:\\ids.txt','r') if row.strip()]' 从第一个样本。
    【解决方案4】:

    快速查看您的 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 哈希通过键快速提取值,以及如何为单个键存储多个值。

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

    【讨论】:

    • 我需要退回他们两个。很抱歉造成混乱。
    • 好的,让事情变得更复杂一些。请参阅上面我修改后的答案。
    • 我正在写它。对不起。我花了一段时间才把它写下来。我应该修改我的答案,然后回复你。
    【解决方案5】:

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

    【讨论】:

      猜你喜欢
      • 2016-06-01
      • 2012-09-16
      • 1970-01-01
      • 1970-01-01
      • 2013-12-07
      • 1970-01-01
      • 1970-01-01
      • 2015-02-23
      • 1970-01-01
      相关资源
      最近更新 更多