in reply to Re^4: setting up boolean parameters from keywords
in thread setting up boolean parameters from keywords

You could try it before posting and get the answer to your own question ;-)

It won't work for a couple of reasons. First, my designates the creation of a lexical variable. You can't do that twice - you'll get two different variables. However, if you change that to:

my %control = map { $_ => 'false' } split ' ', 'play ctrl loop' %control = map { $_ => 'true' } split ' ', $4;
it still won't work (although it will compile/run now). That's because you're assigning one hash to it (created via the first map), and then assigning a second hash to it, completely reinitialising the hash, losing all of the settings from the first time. Like many other things in perl, TMTOWTDI, though. First, I'll explain the logic.

The idea is that you want to set up everything to false, and then reset to true for anything you find. Or, another idea is to set up everything you find to true, and then set everything else to false. Let's try the first one.

my %control = map { $_ => 'false' } qw(play ctrl loop); $control{$_} = 'true' for split ' ', $4;
Here we create the %control hash by using perl's built-in split-on-whitespace operator, qw. This is faster because it can do this split during compilation, rather than each time through the loop. (If it's only done once during your execution, it probably is not much faster, but is a good habit to be in.) Then, we split $4 on whitespace, and set that key in your %control hash to 'true' for each one. Alternately:
my %control = map { $_ => 'false' } qw(play ctrl loop); %control = (%control, map { $_ => 'true' } split ' ', $4);
This one has the same initialisation. However, we use assignment to create a brand new hash, starting out with all the 'false' values, and then adding all the 'true' values. As we're assigning to a hash, perl will automatically discard duplicate keys, saving only the last value. For example, in the initialisation, play will be set to 'false', but if it's in $4, the second line will reset it to 'true' because it's later in the list being assigned.

Second option, setting everything found to true, and setting the rest to false:

my %control = map { $_ => 'true' } split ' ', $4; $control{$_} ||= 'false' for qw(play ctrl loop);
The ||= operator will only set the left variable ($control{$_}) if it isn't set to a true value already. Now, perl isn't going to look at the word "true" and determine that it's true while the word "false" is false. They're both true - the definition of "false" is undef, the number 0, the string '0', or the empty string, ''. The definition of "true" is not false. Thus, the string 'true' is noth undef, the number 0, the string '0', or the empty string, thus must be true. So if the first line has set the value to true, the second line won't change it. Alternately:
my %control = map { $_ => 'true' } split ' ', $4; %control = ((map { $_ => 'false' } qw(play ctrl loop)), %control);
I think by now, you should be able to figure this out. Finally, one last alternative:
my %control = ((map { $_ => 'false' } qw(play ctrl loop)), (map { $_ => 'true' } split ' ', $4));
Here we're doing the same as before, but all in one line.

Now you get to pick which one makes the most sense and is the most readable. Don't pick one just because it's neat and clever - that just makes it harder to read later.

Replies are listed 'Best First'.
Re^6: setting up boolean parameters from keywords
by rand0mmm (Acolyte) on Mar 20, 2006 at 21:57 UTC
    AWESOME reply. Thank you! I did read experiment a bit before I came back. And got this to work...
    $control[0]{"play"} = "/false/; $control[0]{"ctrl"} = "/false/; $control[0]{"loop"} = "/false/; % control = map { $_ => 'true' } split ' ', $4;
    Which I understand much better after reading your post.

    I like your version much more:
    my %control = map { $_ => 'false' } qw(play ctrl loop); $control{$_} = 'true' for split ' ', $4;

    (thanks for qw tip)

    I don't understand in the 2nd to last example,
    my %control = map { $_ => 'true' } split ' ', $4; %control = ((map { $_ => 'false' } qw(play ctrl loop)), %control);

    why the hash is not reinitialized when the 'false's are applied. Isn't this your first caveat at the start of your post? I know it has something to do with the last %control...

    I now also wonder how I would use flags and then assign specific values to the specific options w/o a lot of tests.
    <code> # [src.mov -bfd] b=big, f=fast, etc.. %control = ((map { $_ => 'off' } qw(play ctrl loop)), %control); ?? Thanks Perl Monk!