比较两个Hash数组是否相等

时间:2013-04-03 17:34:30

标签: perl hash compare equality

我想比较数组的两个哈希,看看它们是否相等。也就是说,键值应包含相同的元素。

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)有更好的方法吗?

修改

我想在不使用模块中的函数的情况下执行此操作。

3 个答案:

答案 0 :(得分:4)

尝试使用Test::Deep::NoTest来处理Test::Deep所做的一切,除了它只返回true或false而不输出TAP测试。

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

答案 1 :(得分:3)

Data::Dumper是一个序列化数据结构的核心模块。然后,您可以测试序列化以确保字符串相等。

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

如果偶数Data::Dumper是禁止的,请编写自己的序列化例程,将HoA转换为字符串,并比较字符串。请确保您不会被返回哈希键的随机顺序绊倒(这就是上面示例中$Data::Dumper::Sortkeys=1行的用途)。

答案 2 :(得分:1)

我为每个操作创建单独的subs:测试数组是否相等且是否为哈希:

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

注意:将'ne'更改为'!='或添加逻辑以比较标量值。

由于对每个阵列和其他繁重的数据处理进行排序,您的解决方案并不好。如果你需要对所有类型的哈希进行相等性测试(不仅仅是我的解决方案中的HoA),只需添加标量测试和哈希测试,这将是主要子的递归调用,类似:

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或smth,或者只是将'ne'更改为'!='(但是如果不仅有数字,请注意警告)。