简体   繁体   English

比较Perl中多个哈希值的键值

[英]Compare values of keys across multiple hashes in Perl

I have a set of hashes (with preserved key sequence using Tie::IxHash), and I'd like to compare their values for each key. 我有一组哈希(使用Tie :: IxHash保留键序列),我想比较每个键的值。 The number of hashes can vary. 哈希数可以变化。 For example, I'd like to count how many times the key "1" is assigned the values "1" and "0". 例如,我想计算为键“ 1”分配值“ 1”和“ 0”的次数。 I know there should be a nice fast way to count the value matches if I put the hashes in an array of hashes and then loop through them, but I'm stuck and can't figure it out on my own. 我知道,如果我将哈希值放入一个哈希值数组中然后循环遍历它们,应该有一种很好的快速方法来计算值匹配,但是我被卡住了,无法自行解决。

%hash1 = ( 1 => '1',
           2 => '1',
           3 => '0',
           4 => '0',
         );

%hash2 = ( 1 => '1',
           2 => '1',
           3 => '1',
           4 => '0',
         );

%hash3 = ( 1 => '1',
           2 => '1',
           3 => '0',
           4 => '1',
         );

%hash4 = ( 1 => '1',
           2 => '0',
           3 => '0',
           4 => '1',
         );

The intended result for the above is: 上面的预期结果是:

$key1: $agr1 = 4; $agr0 = 0;
$key2: $agr1 = 3; $agr0 = 1;
$key3: $agr1 = 1; $agr0 = 3;
$key4: $agr1 = 2; $agr0 = 2;

Right now what I ended up doing is looping through the keys of the first hash and then subsequently comparing them to each of the other hashes, which is tedious and stupid for obvious reasons. 现在,我最终要做的是循环遍历第一个哈希的键,然后将它们与其他每个哈希进行比较,由于明显的原因,这很乏味又愚蠢。

Thanks for your help! 谢谢你的帮助!

Correction: I'm using hashes, not hash-refs. 更正:我使用的是哈希,而不是哈希引用。 Edited the above code accordingly. 相应地编辑了上面的代码。

This allows a bit of flexibility in your result as you can put any desired values in @wanted. 您可以在@wanted中输入任何所需的值,从而使结果具有一定的灵活性。 Assumes your hashes are actually hash references (ambiguous in your sample): 假设您的哈希实际上是哈希引用(在示例中是模糊的):

my @hashes = ($hash1,$hash2,$hash3,$hash4);
my %count;
for my $hash (@hashes) {
    $count{ $_ }{ $hash->{$_} }++ for keys %$hash;
}
my @wanted = (1,0);
for my $key (sort { $a <=> $b } keys %count) {
    my @result = map { "agr$_ = " . ($count{$key}{$_} || 0) . ';' } @wanted;
    print "key $key: @result\n";
}

Output: 输出:

key 1: agr1 = 4; agr0 = 0;
key 2: agr1 = 3; agr0 = 1;
key 3: agr1 = 1; agr0 = 3;
key 4: agr1 = 2; agr0 = 2;

Pseudoperl: 伪perl:

# Build a list of refs to your hashes
@a = { \%hash1, \%hash2, ... }

# A container to hold the keys and counts
$keys = {} 

# Initialize the key container
for my $h in @a
    for my $k in %$h
        $keys->{$k} = {0 => 0, 1 => 0} unless exists $keys->{$k}

# Iterate once over all the keys and count occurrences
# assumes input hash values can be only 0 or 1
for my $k in %$keys
    for my $h in @a
        $keys->{$k}->{$h->{$k}}++ if exists $h->{$k};

First, your hash examples are wrong. 首先,您的哈希示例是错误的。 %hash = {} . %hash = {}

If you use the % sigil you want () . 如果您使用%符号,则需要() If you want a hash-ref, it would be $hash = {} . 如果您需要哈希引用, $hash = {}

Back to your question. 回到您的问题。 You could do something like this. 你可以做这样的事情。

Which is commonly referred to as a "seen" hash. 通常称为“可见”哈希。

# appending your example above....
my @arr = (\%hash1, \%hash2, \%hash3, \%hash4);
my $seen = {}; 

# iterate over each hash
for my $hash (@arr) {
    # iterate over each key in hash
    for my $k (keys %$hash) {
        my $val = $hash->{$k};

        # check $val and increment 
        if ($val) {
            $seen->{$k}{1}++;
        } else {
            $seen->{$k}{0}++;
        }   
    }   
}

for my $k ( sort keys %$seen ) { 
    # in case any value is 0/undef
    print "$k:  1 = "
      . ( $seen->{$k}->{0} ? $seen->{$k}->{0} : 0 ) . " 0 = "
      . ( $seen->{$k}->{0} ? $seen->{$k}->{0} : 0 ) . "\n";
}

Which OUTPUTS: 哪些输出:

$ perl test.pl
1:  1 = 0 0 = 0
2:  1 = 1 0 = 1
3:  1 = 3 0 = 3
4:  1 = 2 0 = 2

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM