【问题标题】:How do I compare two hashes in Perl without using Data::Compare?如何在不使用 Data::Compare 的情况下比较 Perl 中的两个哈希?
【发布时间】:2010-11-19 09:44:09
【问题描述】:

如何在不使用 Data::Compare 的情况下比较 Perl 中的两个哈希?

【问题讨论】:

  • 好吧,你看看 Data::Compare 看看他们做了什么。你为什么不想使用那个模块?
  • 不使用 Data::Compare 的一个原因是 Data::Compare 引入了 File::Find::Rule、Number::Compare 和 Text::Glob。我正在尝试简化在我的网络应用中加载的内容,这就是我来到这里的原因。

标签: perl hash


【解决方案1】:

最佳方法因您的目的而异。思南提到的FAQ项目是一个很好的资源:@​​987654321@。在开发和调试期间(当然还有编写单元测试时),我发现Test::More 在比较数组、散列和复杂数据结构时很有用。一个简单的例子:

use strict;
use warnings;

my %some_data = (
    a => [1, 2, 'x'],
    b => { foo => 'bar', biz => 'buz' },
    j => '867-5309',
);

my %other_data = (
    a => [1, 2, 'x'],
    b => { foo => 'bar', biz => 'buz' },
    j => '867-5309x',
);

use Test::More tests => 1;
is_deeply(\%other_data, \%some_data, 'data structures should be the same');

输出:

1..1
not ok 1 - data structures should be the same
#   Failed test 'data structures should be the same'
#   at _x.pl line 19.
#     Structures begin differing at:
#          $got->{j} = '867-5309x'
#     $expected->{j} = '867-5309'
# Looks like you failed 1 test of 1.

【讨论】:

  • 看起来 Test::Deep 的灵感来自 is_deeply。我的问题是如何使 cmp_deeply 成为测试的一部分,而不是单独进行测试?因为我的测试列表只有 8 个,但每次我使用 cmp_deeply 时,它都算作一次测试,当我只有 8 个函数时,我的实际测试数为 11(因为我调用 cmp_deeply 3 次)。我不想增加我的测试次数。有没有更可行的解决方案?
  • @yskhoo。每次调用其中一个测试函数(okcmp_deeply 等)时,它都算作一次测试。据我所知,没有办法避免这种情况。如果您不想提前提交特定数量的测试,可以在加载测试模块时执行此操作:use Test::More qw(no_plan);
  • 您已经在stackoverflow.com/questions/1274756/… 中提出过这个问题。你没有回答为什么你不能增加测试次数,或者你的数据结构有多复杂以至于你需要调用 cmp_deeply 三次。请退后一步,确定真正的问题是什么。如果您愿意提供更多信息,也许我们可以提供帮助。
【解决方案2】:

在谈论哈希时,比较不是一个足够详细的短语。比较哈希的方法有很多:

它们有相同数量的键吗?

if (%a == %b) {
    print "they have the same number of keys\n";
} else {
    print "they don't have the same number of keys\n";
}

两个哈希中的键是否相同?

if (%a != %b) {
    print "they don't have the same number of keys\n";
} else {
    my %cmp = map { $_ => 1 } keys %a;
    for my $key (keys %b) {
        last unless exists $cmp{$key};
        delete $cmp{$key};
    }
    if (%cmp) {
        print "they don't have the same keys\n";
    } else {
        print "they have the same keys\n";
    }
}

它们在两个哈希中是否具有相同的键和相同的值?

if (%a != %b) {
    print "they don't have the same number of keys\n";
} else {
    my %cmp = map { $_ => 1 } keys %a;
    for my $key (keys %b) {
        last unless exists $cmp{$key};
        last unless $a{$key} eq $b{$key};
        delete $cmp{$key};
    }
    if (%cmp) {
        print "they don't have the same keys or values\n";
    } else {
        print "they have the same keys or values\n";
    }
}

它们是同构的吗(我将把它留给读者,因为我不想从头开始尝试实现它)?

或者其他一些相等的度量?

当然,这段代码只处理简单的哈希。添加复杂的数据结构使其更加复杂。

【讨论】:

    【解决方案3】:

    Test::Deep::NoTest 具有相同的功能。

    【讨论】:

      【解决方案4】:

      How do I test whether two arrays or hashes are equal?

      Perl 的常见问题和解答是 Perl 发行版的一部分。您可以通过运行查看perl 随附的此答案的版本:

      $ perldoc -q equal

      在您的终端中。

      【讨论】:

      • FreezeThaw 中的 cmpStr 和 cmpStrHard 有什么区别?
      【解决方案5】:

      又快又脏,而且我肯定效率不高:

      use strict;
      use warnings;
      
      use Data::Dumper;
      
      sub compare ($$) {
          local $Data::Dumper::Terse  = 1;
          local $Data::Dumper::Indent = 0;
          Dumper(shift) eq Dumper(shift);
      }
      
      my %a = ( foo => 'bar', bar => [ 0 .. 3 ] );
      my %b = ( foo => 'bar', bar => [ 0 .. 3 ] );
      my %c = ( foo => 'bar', bar => [ 0 .. 4 ] );
      
      print Dumper compare \%a, \%b;
      print Dumper compare \%a, \%c;
      

      【讨论】:

      • 这种方法加上Text::Diff 打印出一份有用的报告。
      • 你也应该这样做local $Data::Dumper::Sortkeys = 1; 以确保键的顺序相同。
      • @skaurus:为什么?它们的顺序不一样吗?
      • 不起作用。我使用 Perl 5.10 版。这是显示的内容: $VAR1 = ''; $VAR1 = '';
      • @zakovyrya:由于 perl 5.17.6 哈希具有随机密钥顺序。详情请见perldoc.perl.org/perlsec.html#Algorithmic-Complexity-Attacks
      【解决方案6】:

      比较:

      sub HashCompare {
        my ( $a, $b ) = @_;
        my %rhash_1 = %$a;
        my %rhash_2 = %$b;
      
        my $key         = undef;
        my $hash_2_line = undef;
        my $hash_1_line = undef;
      
        foreach $key ( keys(%rhash_2) ) {
         if ( exists( $rhash_1{$key} ) ) {
          if ( $rhash_1{$key} ne $rhash_2{$key} ) {
           print "key $key in $file_1 = $rhash_1{$key} & $rhash_2{$key} in $file_2\n";
               }
             }
           }
           else {
              print "key $key in  $file_1 is not present in $file_2\n";
      
                  #next;
              }
          }
      
          foreach my $comp_key ( keys %rhash_1 ) {
              if ( !exists( $rhash_2{$comp_key} ) ) {
                  print MYFILE "key $comp_key in  $file_2 is not present in $file_1\n";
              }
          }
          return;
      }
      

      创建没有重复键的哈希:

      sub CreateHash {
          my (@key_val_file ) = @_;
          my $key_count      = 1;
          my %hash_key_val   = ();
          my $str4           = undef;
      
          local $/ = undef;
      
          foreach my $each_line (@key_val_file) {
                  @key_val = split( /,/, $each_line );
                  if ( exists( $hash_key_val{$key_val[0]} ) ) {
                          $key_count = $key_count + 1;
                          $str4      = $key_val[0] . " occurence-" . $key_count;
                          $hash_key_val{$str4} = $key_val[1];
                      }
                      else {
                          $hash_key_val{$key_name} = $key_val[1];
                      }
                  }
              }
      
              $key_count = 1;
      
          close FILE;
      
          return %hash_key_val;
      }
      

      【讨论】:

      • 请为您的回答提供解释。
      • $key_name 是从哪里来的?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-09-12
      • 2010-11-17
      • 1970-01-01
      • 1970-01-01
      • 2016-09-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多