Re: Variable-sized hash of booleans

2005-02-05 Thread Randal L. Schwartz
> "Errin" == Errin M HMMA/IT Larsen <[EMAIL PROTECTED]> writes:

Errin>   And furthermore, I will assume that the values in the hash are boolean
Errin> (i.e. '1' (ones) or '0' (zeros)).  Now, I want to see if the WHOLE hash
Errin> is true, this being defined as every key having a value of '1'.

A bit of DeMorgans Laws knowledge helps here:

  "ALL TRUE in my set" can be mapped to "NOT ANY FALSE in my set"

Since the count of items from grep in a scalar context is 0 when ANY
fails and non-zero when ANY succeeds, we can map this to:

NOT  ANY  FALSE in my set
!scalar grep  !$_  , values %things;

And there's the formula!

Cleaning it up a bit:

if (! grep !$_, values %things) {
print "everything is true!\n";
}

-- 
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
 http://www.stonehenge.com/merlyn/>
Perl/Unix/security consulting, Technical writing, Comedy, etc. etc.
See PerlTraining.Stonehenge.com for onsite and open-enrollment Perl training!

-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
 




Re: Variable-sized hash of booleans

2005-02-04 Thread John W. Krahn
Larsen, Errin M HMMA/IT wrote:
Hi everyone,
  As always, we'll start with some necessary code:

#!/usr/bin/perl

use warnings;
use strict;
use Data::Dumper;
  Let's say I have a hash, but I don't know at compile time how many
keys it has in it:
my %things;
die "You have an odd number of arguments.\n" if @ARGV % 2;
$things{shift()} = shift() while( @ARGV );
  And furthermore, I will assume that the values in the hash are boolean
(i.e. '1' (ones) or '0' (zeros)).  Now, I want to see if the WHOLE hash
is true, this being defined as every key having a value of '1'.  If even
one key has a value of '0', I want it to be false.  I decided I could do
this by counting 'true' values:
my $num_things = keys %things;
my $true_things = 0;
foreach( keys %things ) {
  $true_things++ if $things{$_};
}
if( $true_things == $num_things ) {
  print "The \%things hash is true\n";
} else {
  print "The \$things hash is false\n";
}
  But ... This seems less than elegant.  Is there an easier way, perhaps
with map somehow?  I'm not very good at looking at problems and seeing
ways that map can help me.
Well, you could do it like this:
die "You have an odd number of arguments.\n" if @ARGV % 2;
my %things = reverse @ARGV;
my $true_things = "@{[ values %things ]}" =~ /0/ ? 0 : 1;

:-)
John
--
use Perl;
program
fulfillment
--
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
 



RE: Variable-sized hash of booleans

2005-02-04 Thread Larsen, Errin M HMMA/IT
> -Original Message-
> From: Chris Charley [mailto:[EMAIL PROTECTED] 
> Sent: Friday, February 04, 2005 10:45 AM
> To: beginners@perl.org
> Subject: Re: Variable-sized hash of booleans
> 
> 
> > You can use grep.
> >
> > my %hash = (ONE => 1, TWO => 0, THREE => 1);
> >
> > if (grep {! $hash{$_}} keys %hash) {
> > print "false\n";
> > }
> > else {
> > print "true\n";
> > }
> >
> > Prints 'false'.
> 
> Guess it would be helpful to explain how grep works here. 
> From the perlfunc 
> man page:
> Evaluates the BLOCK or EXPR for each element of LIST (locally 
> setting $_ to 
> each element) and returns the list value consisting of those 
> elements for 
> which the expression evaluated to true. In scalar context, 
> returns the 
> number of times the expression was true.
> 
> In the code above, ! $hash{$_} evals to true when $hash{TWO} 
> is evaluated, 
> so grep, being in scalar context, would return 1, the number 
> of elements in 
> %hash which evaluated to 'true '.If all values were 'true', 
> (1's), then grep 
> would return 0 since !$hash{$_} would be false for every 
> element in that 
> case.
> 
> Chris
> 

Oh!

I got my true/false 's backwards cause of the '!' in there.  Thanks for
the explanation Chris.

--Errin

--
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
<http://learn.perl.org/> <http://learn.perl.org/first-response>




RE: Variable-sized hash of booleans

2005-02-04 Thread Larsen, Errin M HMMA/IT
> -Original Message-
> From: Chris Charley [mailto:[EMAIL PROTECTED] 
> Sent: Friday, February 04, 2005 10:21 AM
> To: beginners@perl.org
> Subject: Re: Variable-sized hash of booleans
> 
> 
> You can use grep.
> 
> my %hash = (ONE => 1, TWO => 0, THREE => 1);
> 
> if (grep {! $hash{$_}} keys %hash) {
>  print "false\n";
> }
> else {
>  print "true\n";
> }
> 
> Prints 'false'.
> 
> Chris 
> 

Thanks for the prompt reply, Chris

My mind has the same problem with grep that it does with map.  I don't
know why.  Maybe it's just doing too much at once for me to wrap my
brain around.  What exactly does that grep statement do?  I've read the
perldoc on it, and I still can't grasp it.  Let me try restating what it
does:  grep will iterate through each item in the list, returning a new
list composed of items that the block (or expression) returns true.  Is
that right?  So:
  
  my @new_list = grep {1} @orig_list;

Would set @new_list = @orig_list, and:
  
  my @new_list = grep {0} @orig_list;

Would set @new_list = empty.  Right?  And, in the block (or expression),
$_ will interpolate to each item in the @orig_list.  Have I got it
right?  Also, used in a scalar context, it's gonna give me the number of
returned items, right?  So in your example above, it will break when
there are 2 false values in the original hash?

Nope.  I tried it and it still works with more than one false value.

Can you help me understand what that grep is doing?

--Errin

--
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
<http://learn.perl.org/> <http://learn.perl.org/first-response>




Re: Variable-sized hash of booleans

2005-02-04 Thread Chris Charley
You can use grep.
my %hash = (ONE => 1, TWO => 0, THREE => 1);
if (grep {! $hash{$_}} keys %hash) {
print "false\n";
}
else {
print "true\n";
}
Prints 'false'.
Guess it would be helpful to explain how grep works here. From the perlfunc 
man page:
Evaluates the BLOCK or EXPR for each element of LIST (locally setting $_ to 
each element) and returns the list value consisting of those elements for 
which the expression evaluated to true. In scalar context, returns the 
number of times the expression was true.

In the code above, ! $hash{$_} evals to true when $hash{TWO} is evaluated, 
so grep, being in scalar context, would return 1, the number of elements in 
%hash which evaluated to 'true '.If all values were 'true', (1's), then grep 
would return 0 since !$hash{$_} would be false for every element in that 
case.

Chris

--
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
 



Re: Variable-sized hash of booleans

2005-02-04 Thread Chris Charley
You can use grep.
my %hash = (ONE => 1, TWO => 0, THREE => 1);
if (grep {! $hash{$_}} keys %hash) {
print "false\n";
}
else {
print "true\n";
}
Prints 'false'.
Chris 


--
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
 



Variable-sized hash of booleans

2005-02-04 Thread Larsen, Errin M HMMA/IT
Hi everyone,

  As always, we'll start with some necessary code:

#!/usr/bin/perl

use warnings;
use strict;
use Data::Dumper;

  Let's say I have a hash, but I don't know at compile time how many
keys it has in it:

my %things;
die "You have an odd number of arguments.\n" if @ARGV % 2;
$things{shift()} = shift() while( @ARGV );

  And furthermore, I will assume that the values in the hash are boolean
(i.e. '1' (ones) or '0' (zeros)).  Now, I want to see if the WHOLE hash
is true, this being defined as every key having a value of '1'.  If even
one key has a value of '0', I want it to be false.  I decided I could do
this by counting 'true' values:

my $num_things = keys %things;
my $true_things = 0;

foreach( keys %things ) {
  $true_things++ if $things{$_};
}

if( $true_things == $num_things ) {
  print "The \%things hash is true\n";
} else {
  print "The \$things hash is false\n";
}

  But ... This seems less than elegant.  Is there an easier way, perhaps
with map somehow?  I'm not very good at looking at problems and seeing
ways that map can help me.

  With this last bit of code I can check the validity of the true/false
test:

print Dumper( \%things );

  The whole code together is here:

#!/usr/bin/perl

use warnings;
use strict;
use Data::Dumper;

my %things;
die "You have an odd number of arguments.\n" if @ARGV % 2;
$things{shift()} = shift() while( @ARGV );

my $num_things = keys %things;
my $true_things = 0;

foreach( keys %things ) {
  $true_things++ if $things{$_};
}

if( $true_things == $num_things ) {
  print "The \%things hash is true\n";
} else {
  print "The \$things hash is false\n";
}

Print Dumper( \%things );


  Now, my output looks like this:

# things_test 1 One 1 Two 1 Three
The %things hash is true
$VAR1 = {
  'Three' => '1',
  'Two' => '1',
  'One' => '1'
};

  Or ... A false one:

# things_test 1 One 0 Two 1 Three
The %things hash is false
$VAR1 = {
  'Three' => '1',
  'Two' => '0',
  'One' => '1'
};

Thanks in advance for any help!

--Errin

--
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]