2012-07-20 14 views
2

我有一个制表符分隔的文件(inpFile.txt)作为阅读Perl中的制表符分隔的文件转换成散列和搜索

field1 field2 
aaa1 aaa2 
aaa1 bbb2 
aaa1 ccc2 
ccc1 ddd2 
eee2 aaa2 

我想读它,并将其存储到哈希(hashname)

一旦我的哈希准备就绪,我想搜索是否找到($ key,$ value)对。例如,如果找到(eee2,aaa2)?

我是Perl的入门者,但我知道它可以在Perl中高效地完成并且很容易。

我写了下面的代码。你能否进一步扩展它?

感谢

#!/usr/local/bin/perl 

open (LIST1, "/inpFile.txt") || die "File not found\n"; 
    while (<LIST1>) { 
      ($tmpvar1, $tmpvar2) = split(/\t/, $_); 
      $hashname{$tmpvar1} = $tmpvar2; 
    } 
close(LIST1); 
+0

谢谢,您问题中的代码片段实际上是我的解决方案! – 2015-07-14 00:45:55

回答

0

输入文件将导致只有三个元素的哈希,因为键重复。在现实生活中,你有但是对付那种情况,在这种情况下,我改变你的输入文件:

aaa1 aaa2 
bbb1 bbb2 
ccc1 ccc2 
ccc1 ddd2 
eee2 aaa2 

下面是一些增强功能代码:

#!/usr/local/bin/perl 

#always use strict and warnings 
use strict; 
use warnings; 
use Data::Dumper; 

hash_test(); 
#Try to put your code in separate subs if possible 
sub hash_test { 
    my %hashname =(); 
    read_into_hash(\%hashname); 
    print Dumper(\%hashname); # Test your hash 
    search_hash(\%hashname, "eee2", "aaa2"); 
} 

sub read_into_hash { 

    #Always declare variables 
    my $list1; 
    my $tmpvar1; 
    my $tmpvar2; 
    my $hash_ref = shift; 
    my $lineno = 0; 
    open($list1, "<", "/inpFile.txt") or die "File not found\n"; 
    while (<$list1>) { 
     $lineno++; 
     chomp; #delete new line character 
     ($tmpvar1, $tmpvar2) = split(/\t/, $_); 
     if (defined $hash_ref->{$tmpvar1}) 
     { 
     # adding lineno from file to avoid overwriting. I use '~' just in case 
     # if your keys could include such character, use something else 
     $tmpvar1 .= "~" . $lineno; 
     } 
     $hash_ref->{$tmpvar1} = $tmpvar2; 

    } 

    close($list1); 
} 

sub search_hash { 
    my $hash_ref = shift; 
    my $key  = shift; 
    my $value = shift; 

    if (defined $hash_ref->{$key} && $hash_ref->{$key} =~ /^$value(\~\d+)*$/) 
    { 
      print "Found.\n"; 
     } 
} 
+0

我的数据有一个与多个值关联的密钥。 Ca代码处理这种情况?在我的例子中,aaa1与aaa2,bbb2和ccc2都有关联。这可能为同一个键有不同的值。或者还有其他方法可以有效地做到这一点。我的文件比演出多。 – learner 2012-07-20 03:54:04

+0

更改了代码以处理密钥重复问题。搜索子也被改变。 – Hameed 2012-07-20 03:57:13

+0

另请注意,我使用'print Dumper($ hashname)'来测试散列元素的原因。如果你处理这么大的文件,就把它拿出来。 – Hameed 2012-07-20 04:03:02

0

首先,当你遇到Perl,请使用pragma use strict;

我注意到你的文件处理我们的文件中包含

aaa1 aaa2 
aaa1 bbb2 

,哈希将存储只需一键'aaa1' => 'bbb2',因为Perl有哈希唯一键。

use strict; 

open my $fh, '<', '/input_file.txt' 
    or die "Cant open file $!"; 

LINE: 
while (my $line = <$fh>) { 
    my ($key, $value) = split /\t/, $line; 
    next LINE if not $key; 

    $hash{$key} = $value; 
} 

my $search_key = 'eee2'; 
my $search_value = 'aaa2'; 

if ($hash{$search_key} eq $search_value) { 

    print "Found key: $search_key and value: $search_value in hash /n"; 
} 

close $fh; 
+0

其实我的数据与我提到的形式相同。这可能为同一个键有不同的值。或者还有其他方法可以有效地做到这一点。我的文件比演出多。 – learner 2012-07-20 03:51:21

+0

然后,您必须添加另一个级别来对相同的密钥进行散列或添加前缀/后缀。 – Hameed 2012-07-20 03:54:10

1

首先,我理解你的问题具体到对愚弄键/值对。这有些尴尬 - 正常的问题只是测试密钥,但我们可以通过将密钥和值都输入到生成新密钥的函数来完成密钥值。

如果您只是使用制表符分隔的CSV,请使用Text::CSV并放心,它是正确的,并且涵盖了最复杂的情​​况!安装Text::CSV_XS也使它非常快。

use strict; 
use warnings; 
use Data::Dumper; 
use Text::CSV; 
use IO::Handle; 

my $csv = Text::CSV->new({sep_char=>"\t"}); 
my $fh = IO::Handle->new_from_fd(*DATA, 'r'); 

while (not $fh->eof) { 
    my $row = $csv->getline($fh); 
    warn Dumper $row; 
} 

__DATA__ 
aa1 aaa2 
aaa1 bbb2 
aaa1 ccc2 
ccc1 ddd2 
eee2 aaa2 

当你明白了之后,其余练习也很简单。我使用了一个非常简单的算法,它将key和value连接起来,并且通过它来索引hash。这消除了碰撞时的狡猾尝试,但可能不是您的任务所必需的。随意问的问题。

use feature ':5.10'; 
use strict; 
use warnings; 
use Data::Dumper; 
use Text::CSV; 
use IO::Handle; 
use Digest::SHA qw(sha1_hex); 

my $csv = Text::CSV->new({sep_char=>"\t"}); 
my $fh = IO::Handle->new_from_fd(*DATA, 'r'); 

my (%kv, %sha1_kv); 
while (not $fh->eof) { 
    my $row = $csv->getline($fh); 
    my ($k, $v) = @$row; 

    my $sha1 = sha1_hex($k) . sha1_hex($v); 

    if (exists $sha1_kv{ $sha1 }) { 
    say "We have a hit (key/value dupe) for $sha1 [key: $k]"; 
    } 
    else { 
    $kv{ $k } = $v; 
    $sha1_kv{ $sha1 } = $v; 
    } 

    warn Dumper $row; 
} 

__DATA__ 
aa1 aaa2 
aa1 aaa2 
aaa1 bbb2 
aaa1 ccc2 
ccc1 ddd2 
eee2 aaa2 
2

由于您的数据包含有多个值的键,并假设实际上在你的数据文件的情况下,你可以创建数组(HOA),其中一个关键是与阵列相关联的哈希值:

use Modern::Perl; 

my %hashname; 

while (<DATA>) { 
    my ($key, $value) = split; 
    push @{ $hashname{$key} }, $value; 
} 

my $searchKey = 'aaa1'; 
my $searchVal = 'ccc2'; 

if (defined $hashname{$searchKey} 
    and $searchVal ~~ @{ $hashname{$searchKey} }) 
{ 
    say "key: $searchKey with val: $searchVal found."; 
} 
else { 
    say "key: $searchKey with val: $searchVal not found."; 
} 

__DATA__ 
aaa1 aaa2 
aaa1 bbb2 
aaa1 ccc2 
ccc1 ddd2 
eee2 aaa2 

通过首先查看是否存在关键字,然后使用智能匹配运算符来查看与该关键字相关联的数组中是否存在该值,从而搜索“键/值”对。

输出:

key: aaa1 with val: ccc2 found. 

希望这有助于!

相关问题