Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I have a few checkboxes on a form. I am trying to convert the ticked checkbox to 'yes', unchecked to 'no'.

I thought I could do the following:

my @array = qw($one $two $three); foreach my $item (@array){ if ($item) { $item = 'yes'; } else { $item = 'no'; }
But actually changes all $item to 'yes'

Could anyone tell me what I am doing wrong and how I might achieve these chqnges.

Thanks

Replies are listed 'Best First'.
Re: Changing each item in an array
by diotalevi (Canon) on Jul 18, 2003 at 23:34 UTC

    Your @array variable contains three strings: '$one', '$two', and '$three'. Try it again as my @array = ($one, $two, $three). And pick better names. Those are atrocious and are absolutely uncommunicative about their purpose.

    Added: I should mention that doing things this way means the copy of the value in @array is now altered, the original contents of $one, $two and $three will remain unaltered. You need references to alter the original variables. Your code then looks like this:

    my @array = ( \ $one, \ $two, \ $three); foreach my $item (@array){ if ($$item) { $$item = 'yes'; } else { $$item = 'no'; } }
      diotalevi,
      I know that this was probably a contrived example by the Anonymous Monk to illustrate the problem, but in this case I would probably:
      for my $item ($one, $two, $three) { $item = $item ? 'yes' : 'no'; }
      This gets rid of the array all together and the need to dereference. I realize that the for loop is magically creating the reference and doing the dereference implicitly aliasing for you, but it is transparent. Hmmm - may I should get rid of that ternary operator if my point was for simplicity/clarity to the Anonymous Monk - nah!

      Cheers - L~R
      updated: Modified verbiage per diotalevi's clarification

        No, foreach doesn't create a reference and dereference for you. Really. Its an internals thing and it *aliases* the loop variable. This is really outside the bounds of what I think will confuse the original poster though. I also would normally have used ternary assignment but, again, in the interests of speaking to the original poster's knowledge level I kept the same if/else syntax and just changed the bits that needed to be.

Re: Changing each item in an array
by Abigail-II (Bishop) on Jul 19, 2003 at 11:11 UTC
    Whenever someone says "I want to do something for each element of an array or list", I think "map". Will the following do?
    my @array = map {$_ ? "yes" : "no"} ($one, $two, $three);

    Abigail

•Re: Changing each item in an array
by merlyn (Sage) on Jul 18, 2003 at 23:54 UTC
(jeffa) Re: Changing each item in an array
by jeffa (Bishop) on Jul 19, 2003 at 01:42 UTC
    You should use an array or a hash instead of separate variables. What happens when you add $four, $five, and $five_hundred_fifty_five? I have no idea how you are setting $one, $two, and $three, but i'll bet it's not pretty.

    You don't have to use CGI.pm, but here is an example script that does. The usage for CGI.pm's checkbox_group() method is quite daunting - i still have to refer to the docs (and sprinkly a little chicken blood) when using it. The key is to create a hash whose keys are the values of the checkbox, and whose values are the labels of the checkbox (i wish that were the other way around, btw). For example:

    my %label = ( one => 'foo', two => 'bar', three => 'baz', );
    From here, it's just a matter of faith to create a checkbox_group:
    print checkbox_group( -name => 'checkbox', -values => [keys %label], -labels => \%label, );
    But now that that complexity is over, look how easy it is to create another hash whose keys are one, two, and three, and whose values are either yes or no:
    # create an array whose keys all have values 'no' my %checkbox = map { $_ => 'no' } keys %label; # update each found key's value to 'yes' $checkbox{$_} = 'yes' for param('checkbox');
    Here is a complete script that you can tinker with: Hope this helps. :)

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
Re: Changing each item in an array
by bobn (Chaplain) on Jul 18, 2003 at 23:39 UTC

    This code is behaving as expected. "if ($item)" is true, as long as $item is defined and has a value other than number 0, the string '0' or the string ''.

    So we'll need something closer to your actaul code to understand what you're trying to accomplish

    --Bob Niederman, http://bob-n.com
Re: Changing each item in an array
by Jenda (Abbot) on Jul 19, 2003 at 18:10 UTC

    You already have enough answers to your immediate question so I'll just add an advice:

    If the code behaves funny, test whether the data look the way you expected.

    In this case the very first thing should should have done is printing either the contents of @array or the value of $item before you modified it. Eg.

    print "\@array = ( '" . join( "', '", @array) . "')\n";
    If you did this you'd see that the @array contains the variable NAMES, not their values.

    Jenda
    Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.
       -- Rick Osborne

    Edit by castaway: Closed small tag in signature