【问题标题】:reading a tab delimited file into hash in perl and search在 perl 中将制表符分隔的文件读入哈希并搜索
【发布时间】:2012-07-20 03:10:50
【问题描述】:

我有一个制表符分隔文件 (inpFile.txt)

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);

【问题讨论】:

  • 谢谢,您问题中的代码 sn-p 实际上是我的解决方案!

标签: perl search hash


【解决方案1】:

由于您的数据包含具有多个值的键,并且假设您的数据文件中确实是这种情况,您可以创建一个数组哈希 (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.

希望这会有所帮助!

【讨论】:

    【解决方案2】:

    首先,我将您的问题解释为特定于键/值上的欺骗。这有点尴尬——通常的问题只是测试键,但我们可以通过将键和值都作为生成新键的函数的输入来进行键值对。

    如果您只是使用制表符分隔的 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
    

    了解了这些之后,剩下的练习也很简单。我使用了一个非常简单的算法,它将键和值连接起来,并以此为哈希索引。这消除了狡猾的碰撞尝试,但可能不是您的任务所必需的。随时提问。

    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
    

    【讨论】:

      【解决方案3】:

      第一次遇到 Perl 时,请使用 pragma use strict;

      我注意到你的文件包含

      aaa1  aaa2
      aaa1  bbb2
      

      在处理我们的文件时,hash 将只存储一个键 'aaa1' =&gt; 'bbb2',因为 Perl 在 hash 中具有唯一键。

      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;
      

      【讨论】:

      • 实际上我的数据与我提到的形式相同。这是否可能对同一个键有不同的值。或者有没有其他方法可以有效地做到这一点。我的文件不仅仅是演出。
      • 您将不得不添加另一个级别来散列或为相同的键添加前缀/后缀。
      【解决方案4】:

      Y我们的输入文件将只产生三个元素散列,因为键是重复的。在现实生活中,您必须处理这种情况,但是在这种情况下,我会更改您的输入文件:

      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";
             }
      }
      

      【讨论】:

      • 我的数据有一个键与多个值相关联。 Ca这段代码处理这种情况?在我的示例中,aaa1 与 aaa2、bbb2 和 ccc2 所有相关联。这是否可能对同一个键有不同的值。或者有没有其他方法可以有效地做到这一点。我的文件不仅仅是演出。
      • 修改了代码处理密钥重复问题。搜索子也发生了变化。
      • 另外请注意,我使用print Dumper($hashname) 来测试哈希元素的原因。如果你处理这么大的文件,就把它拿出来。
      猜你喜欢
      • 2019-10-22
      • 2019-05-10
      • 2011-11-29
      • 1970-01-01
      • 2018-12-29
      • 2013-09-26
      • 1970-01-01
      • 1970-01-01
      • 2014-12-23
      相关资源
      最近更新 更多