ado
ado

Reputation: 1471

How to test whether all values of a hash equal a given value

I'm dealing with hashes like:

my %hash1 = (
  key1 => 0,
  key2 => 1,
  key3 => 0,
);

I want to do something if the value of all values (not just one value) of %hash1 is 1.

How to write that?

For reference, I can write:

for $key ( keys %hash1 ) {
   if ( $hash1{$key} == 1 ){
    #do something
   }
}

which is wrong because even if one key has a value equal to 1, the #do something part of the code will run. The code I wrote apparently does something if at least one key equals 1. It would be nice to have something like:

for $key ( keys %hash1 ) {
   if ( exists( $hash1{$key} == 1 ) ){
    #do something
   }
}

Upvotes: 1

Views: 1966

Answers (3)

amon
amon

Reputation: 57646

You can use List::MoreUtils:

use List::MoreUtils qw/all/;

if (all { $_ == 1 } values %hash) {
  # iterate the hash
  while (my ($k, $v) = each %hash) {
    ...
  }
}

The all { something($_) } @list is a fancy way of writing

!grep { !something($_) } @list

which uses De Morgan's Law.

Note that my %hash = { key => 1 } does not create the data structure you wanted. Rather, this maps a key "HASH(0x1234567)" to undef. If you use warnings, you'll get a message telling you that you are using a (hash) reference where a list was expected. Initialize hashes with a key-value list: my %hash = ( key => 1).

Upvotes: 4

Toto
Toto

Reputation: 91518

I'd do:

my $not_all_ones = grep { $_ != 1 } values %hash1;

Upvotes: 6

Karthik T
Karthik T

Reputation: 31972

Set a flag within the if and check its value after the loop.

$all_are_one = $all_are_one && $hash1{$key} == 1

You would need to set it to true before the loop

Upvotes: 2

Related Questions