2013-04-03 90 views
3

我想比較兩個哈希值的數組,以查看它們是否相等。也就是說,關鍵值應該包含相同的元素。比較兩個散列的哈希值是否相等

my %h1 = (
    w1 => ['3','1','2'], 
    e2 => ['6','2','4'], 
    r1 => ['8', '1'], 
); 

my %h2 = (
    w1 => ['3','1','2'], 
    e2 => ['6','2','4'], 
    r1 => ['8','1'], 
); 

my %h3 = (
    w1 => ['3','1','2'], 
    e2 => ['6','2','4'], 
    r1 => ['4','1'], 
); 

my $i = 0; 

foreach (keys %h2){ 
    my $conditional = scalar keys %h2; # 3 
    if ([sort @{$h1{$_}}] ~~ [sort @{$h2{$_}}]) { 
     $i++; 
    } 
    if ($i eq $conditional){ 
     print "true\n"; 
    } 
} 

比較%h1和,因爲他們是平等的%h2應返回true。比較%h1%h3什麼都不打印。 1)有沒有更好的方法來做到這一點?

編輯

我想做到這一點,而無需使用功能從一個模塊。

回答

4

嘗試Test::Deep::NoTest,它處理所有Test::Deep所做的一切,除非它只是在不輸出TAP測試的情況下返回true或false。

print "true" if eq_deeply(\%h1, \%h2) 
+0

如何在不使用模塊的情況下執行此操作? – cooldood3490

+1

@ cooldood3490 - 你有沒有特別的理由不能使用模塊? – frezik

+1

這是一個任務。我想學習。 :-) – cooldood3490

3

Data::Dumper是一個核心模塊,串行化的數據結構。然後你可以測試字符串相等的序列化。

use Data::Dumper; 
$Data::Dumper::Sortkeys = 1; 
if (Dumper(\%hash1) eq Dumper(\%hash2)) { 
    print "hashes are equal\n"; 
} 

如果連Data::Dumper是禁地,寫自己的序列化例程,它的家鄉地址轉換爲字符串,然後比較字符串。只要確保你不會被散列鍵返回的隨機順序絆倒(這就是上面例子中的$Data::Dumper::Sortkeys=1行)。

+0

這很好,但我試圖沒有模塊做到這一點。 – cooldood3490

+1

實際上,在5.18中,訂單將是真正隨機的,而不僅僅是隨機的。 [另見](https://www.google.com/search?q=5.18+perl+random+hash) –

1

我會爲每一個操作單獨替補:測試如果數組相等,且同爲哈希:

sub is_arrays_equal($$) { 
    my ($a, $b) = @_; 
    if (scalar @$a != scalar @$b) { 
     return 0; 
    } 
    for my $i (0 .. $#{$a}) { 
     if ($a->[$i] ne $b->[$i]) { 
      return 0; 
     } 
    } 
    return 1; 
} 

sub is_hoa_equal($$) { 
    my ($a, $b) = @_; 
    if (scalar(keys %$a) != scalar(keys %$b)) { 
     return 0; 
    } 
    for my $k (keys %$a) { 
     if (exists $b->{$k}) { 
      if (ref $a->{$k} ne 'ARRAY' || ref $b->{$k} ne 'ARRAY' || !is_arrays_equal($a->{$k}, $b->{$k})) { 
       return 0; 
      } 
     } 
     else { 
      return 0; 
     } 
    } 
    return 1; 
} 

注:改變「東北」到「!=」或添加邏輯來比較標量值。

您的解決方案不好,因爲排序每個陣列和其他重型數據處理。如果你對所有類型的哈希(不僅爲家鄉地址在我的解決方案),只需添加標測試和哈希測試,這將是主子的遞歸調用,這樣的事情需要平等的測試:

sub arrays_equal { 
    my ($a, $b) = @_; 
    if (scalar @$a != scalar @$b) { 
     return 0; 
    } 
    for my $i (0 .. $#{$a}) { 
     my $va = $a->[$i]; 
     my $vb = $b->[$i]; 
     if (ref $va ne ref $vb) { 
      return 0; 
     } 
     elsif (ref $va eq 'SCALAR' && $va ne $vb) { 
      return 0; 
     } 
     elsif (ref $va eq 'ARRAY' && !arrays_equal($va, $vb)) { 
      return 0; 
     } 
     elsif (ref $va eq 'HASH' && !hashes_equal($va, $vb)) { 
      return 0; 
     } 
    } 
    return 1; 
} 

sub hashes_equal { 
    my ($a, $b) = @_; 
    if (scalar(keys %$a) != scalar(keys %$b)) { 
     return 0; 
    } 
    for my $k (keys %$a) { 
     if (exists $b->{$k}) { 
      my $va = $a->{$k}; 
      my $vb = $b->{$k}; 
      if (ref $va ne ref $vb) { 
       return 0; 
      } 
      elsif (ref $va eq 'SCALAR' && $va ne $vb) { 
       return 0; 
      } 
      elsif (ref $va eq 'ARRAY' && !arrays_equal($va, $vb)) { 
       return 0; 
      } 
      elsif (ref $va eq 'HASH' && !hashes_equal($va, $vb)) { 
       return 0; 
      } 
     } 
     else { 
      return 0; 
     } 
    } 
    return 1; 
} 

此代碼檢查標量爲字符串。你可以添加is_number或者像那樣,或者只是將'ne'改爲'!='(但是如果不僅僅是數字,請小心警告)。