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

Hi: Does anybody know how to update an array of strings. I have an array of strings. I want to match and substitute a particular string. I then want to put the new string back to its original place in the array. --thanks kirk

Replies are listed 'Best First'.
Re: updating an array of strings
by grantm (Parson) on Aug 26, 2002 at 01:34 UTC

    The right way to do this is simply to use 'foreach'. Eg to replace every occurence of 'cat' with 'dog':

    foreach (@strings) { s/cat/dog/g; }

    A common error is to use 'map':

    map { s/cat/dog/g; } @strings;

    The point of map is that it returns a copy of the transformed list. If you don't want a new list, but just want to transform the list 'in place', use foreach.

(jeffa) Re: updating an array of strings
by jeffa (Bishop) on Aug 26, 2002 at 01:26 UTC
    Here is one way - say you want to replace 'baz' with 'qux':
    use strict; my @array = qw(foo bar bazzle baz); @array = map { s/^baz$/qux/;$_ } @array;
    This will replace all occurances of 'baz' in the array however. You didn't specify if this is okay or not.

    UPDATE: oops - yet another problem to not solve with map. Thanks for the tip grantm and Anony. :)

    So ... let's say that you only wanted to replace the first occurrance of 'baz':
    my @array = qw(foo bazzle baz baz); for (@array) { last if s/^baz$/qux/; }
    much better, just don't try this with a list:
    for (qw(foo bazzle baz baz)) { last if s/^baz$/qux/; }
    which will not work, because you are trying to modify read-only values.

    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)
    
      Or even simpler:
      s/^baz$/qux/ for @array;

      Oops sorry jeffa, my reply (below, but typed before I saw yours) looks kind of confrontational :-(

      My understanding was that the map in your example would edit each element in place (via the 's/...') and then the assignment to @array would needlessly replace each element with a copy of the resulting string.

      jeffa, Thanks for helping me. --kirk
Re: updating an array of strings
by rob_au (Abbot) on Aug 26, 2002 at 01:45 UTC
    A better approach than those suggested if you have a large array of information would be to make use of the splice function - This allows you to change an array element, O(1) execution, in place without iterating over the entire array, O(n) execution. For example:

    my @array = ( 'foo', 'moo', 'baz' ); splice @array, 1, 1, 'bar';

    The downside to this approach is that you will need to know the array position of the string which you are looking at modifying. If you do not know this index, then you would be better off exploring a loop or map construct as suggested and depending upon your requirements - Also of interest might be this node.

     

      splice is not what you are looking for. A simple assignment is the clearest and most efficient way to update the value of an array element with a known index.

      my @array = qw(foo moo baz); $array[1] = 'bar';

      — Arien

        Perl never ceases to amaze me. After seeing Arien's point I wondered just how much slower it was to build a stack frame, do the assignment and knock the stack frame down again.

        I've seen various references to "the overhead of calling a sub" and have been guilty of not sub-ing when I should have because of it. I needn't have worried. I was expecting a vastly higher overhead than this demonstrates!

        #!perl -w use strict; use Benchmark; my @ary = 0 .. 100; Benchmark::cmpthese ( 10_000_000, { 'assignment' => '$ary[1] = -1;', 'splice' => 'splice @ary, 1, 1, -1;' } ); __END__ # Output C:\test>192779 Benchmark: timing 10000000 iterations of assignment, splice... assignment: 21 wallclock secs (19.65 usr + 0.00 sys = 19.65 CPU) @ 50 +8931.75/s (n=10000000) splice: 56 wallclock secs (57.13 usr + 0.01 sys = 57.14 CPU) @ 17 +4999.56/s (n=10000000) Rate splice assignment splice 175000/s -- -66% assignment 508932/s 191% --

        What's this about a "crooked mitre"? I'm good at woodwork!