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

Hello all,

Is there a way to do

my @fields = qw/this that the_other/; foreach (@fields) { $_ =~ s/^|$/"/g; }

without an explicit loop, i.e. by doing something to the array as whole?

Thanks,

loris

Replies are listed 'Best First'.
Re: Applying regex to array
by kappa (Chaplain) on Nov 24, 2004 at 10:34 UTC

    And you could use one of those loop statement modifiers, they fit nicely.

    s/^|$/"/g for @fields;

    But that's semanticaly a loop, however.

    --kap
Re: Applying regex to array
by chb (Deacon) on Nov 24, 2004 at 10:22 UTC
    You could use map:
    my @fields = qw/this that the_other/; map { s/^|$/"/g; } @fields;

      Using map in a void context is bad. Perl expects map to return a list, so it wastes time building up a return list which just gets thrown away. I've heard figures that show it to be 10% slower.

      I'd just use for.

      s/^|$/"/g for @fields;

      I understand this is being worked on for new versions of Perl. There's no reason why map can't work out that it's being called in void context and not build up the return list.

      Update: You can safely ignore this advice if you're using Perl 5.8.1 or greater (see perl581delta). Personally, I still think it's an abuse of map when foreach can be used to do the same thing. But YMMV :)

      Update (again): Limbic~Region points me at this previous discussion of these points (particularly Abigail's reply here. Having read it thru, it seems to me that tilly sums up my point of view pretty well.

      --
      <http://www.dave.org.uk>

      "The first rule of Perl club is you do not talk about Perl club."
      -- Chip Salzenberg

        Personally, I still think it's an abuse of map when foreach can be used to do the same thing. But YMMV :)

        I used to think that, but it's such a common thing to be suggested that I think it's worth asking why. Actually, I also think I have an answer. This paper on natural programming languages has some interesting things to say about how people naturally think about solving problems:

        Aggregate operators (acting on a set of objects all at once) were used much more often than iterating through the set and acting on the objects individually. For example, "Move everyone below the 5th place down by one."

        While one can argue the meaning of this, this and the rest of the paper suggested to me that programming in a way that matches how people (not necessarily just programmers) think is more likely to produce good code. The paper is an interesting read.

        Cheers,
        Ovid

        New address of my CGI Course.

        I started to reply to this before I read the last paragraph, but I may as well keep going. I thought map in void context had already been optimised in the newest versions. That's what I'd heard, anyway.
Re: Applying regex to array
by ysth (Canon) on Nov 24, 2004 at 10:59 UTC
    Making some assumptions about your data (untested):
    @fields = split /(?<=")(?=")/, '"'.join('""', @fields).'"';
    But most people would find it simpler to use a loop to perform a looping operation. At least until hyper-ops are available...
Re: Applying regex to array
by si_lence (Deacon) on Nov 24, 2004 at 10:39 UTC
    You can use map or grep as shown by chb and howie.
    But this just makes the loop implicit.
    Depending on your way of thinking and reading code it might
    be easier to see what is going on with your original construct.
    Just a thought.
    si_lence
Re: Applying regex to array
by Roy Johnson (Monsignor) on Nov 24, 2004 at 16:41 UTC
    What are you hoping to accomplish?

    Caution: Contents may have been coded under pressure.
Re: Applying regex to array
by revdiablo (Prior) on Nov 24, 2004 at 19:30 UTC

    With all the talk of map and side effects, I thought it might be nice to show you a version using map with no side effects. I actually kind of prefer this:

    my @fields = qw/this that the_other/; @fields = map { qq("$_") } @fields;

    Sure, it copies @fields instead of modifying it in place, but I doubt that makes a significant different in performance (most of the time). I think this is much clearer in expressing your intentions than using s/// with the for loop.

Re: Applying regex to array
by howie (Sexton) on Nov 24, 2004 at 10:33 UTC
    @fields = qw/this that the_other/; @fields = grep { s/t/j/ } @fields; print join(" ",@fields);
    Like that? (ignore all this - I'm dozy. See below)

      I don't really understand why you've chosen to use grep here instead of map. With grep you'll lose any elements where the substitution didn't change anything.

      my @fields = qw/this is the_other/; @fields = grep { s/t/j/ } @fields; print "@fields"; # prints "jhis jhe_other" (losing "is")
      --
      <http://www.dave.org.uk>

      "The first rule of Perl club is you do not talk about Perl club."
      -- Chip Salzenberg