http://www.perlmonks.org?node_id=1098038

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

If I am to concatenate two elements of an array, will the index numbers assigned to the array elements update? In other words, if I were to run this code:

@array = (1..10);

$array[7] = $array[7] . $array[8];

My array now has the following elements:

1

2

3

4

5

6

78

9

10

Is the index of 9 still $array[9]? Or has it been bumped up to $array[8] since the number that was in $array[8] has been concatenated with $array[7]?

I've tried searching for this online, but couldn't find anything...maybe I'm using incorrect terminology?

Thanks a lot!

- Lisa

Replies are listed 'Best First'.
Re: Concatenating Array elements
by davido (Cardinal) on Aug 19, 2014 at 20:46 UTC

    Your example demonstrates an off-by-one error: $array[7] contained 8 to begin with, and afterward, would contain 89.

    This is one of those things that you could easily try yourself. If you have Perl installed, you would do this:

    my @array = ( 1 .. 10 ); $array[7] = $array[7] . $array[8]; print "$array[7]\n"; print "$array[8]\n";

    And you will see the following output:

    89 9

    ...which would tell you that $array[8] hasn't been modified in any way. As a matter of fact, it would be a really difficult to use language if something as innocuous as the concatenation operator could modify its operands (not counting stringification). Imagine this:

    my @array = ( 1 .. 10 ); $array[7] = $array[7] + $array[8]; print "$array[7]\n"; print "$array[8]\n";

    There, you would expect to see:

    17 9

    And you would complain if simple addition caused one of the operands to vaporize. Concatenation is not so different, in this regard.

    Now if it is your intention to vaporize an element in an array and shift everything past that point up to fill the void, look at splice, but be forewarned that shifting elements to lower indices is an O(n) operation, meaning that it consumes as much computational time as it takes to shift one element, then to shift the next one, then to shift the next one, and so on, until done -- as the array grows, the time grows linearly.


    Dave

Re: Concatenating Array elements
by muba (Priest) on Aug 19, 2014 at 20:39 UTC

    Your code will only modify the value of $array[7] (which was 8: remember that array indexes start at 0, not at 1). In other words, after $array[7] = $array[7] + $array[8], your array will contain (1, 2, 3, 4, 5, 6, 7, "89", 9, 10).

    The index of the element with value 9 is still 8 as it has always been (again, array indexes start at 0, not at 1). No elements have been moved around or deleted. Only the 8th element (the one with index 7) has been altered.

Re: Concatenating Array elements
by johngg (Canon) on Aug 19, 2014 at 22:36 UTC

    Others have explained why the code you posted is not giving you the results you expect and have pointed out that splice is perhaps the tool for what you are trying to do. Because splice modifies the length of an array, and consequently the index values for elements to the right of the operation, it is best if operating on more than one element to work from right to left. You can use reverse to achieve this.

    $ perl -Mstrict -Mwarnings -E ' my @arr = q{0} .. q{9}; for my $idx ( grep { $_ % 2 } reverse 0 .. $#arr ) { $arr[ $idx - 1 ] .= splice @arr, $idx, 1; } say for @arr;' 01 23 45 67 89 $

    I hope this is helpful.

    Cheers,

    JohnGG

Re: Concatenating Array elements
by frozenwithjoy (Priest) on Aug 19, 2014 at 20:47 UTC
    First off, arrays have a 0-based index. For example:
    my @array = 1..10; print "Index 7 (before): $array[7]\n"; print "Index 8 (before): $array[8]\n"; $array[7] = $array[7] . $array[8]; print "Index 7 (after): $array[7]\n"; print "Index 8 (after): $array[8]\n";

    Would yield:

    Index 7 (before): 8 Index 8 (before): 9 Index 7 (after): 89 Index 8 (after): 9

    If you want to have an element disappear when concatenated elsewhere, you could use splice:

    $array[7] = $array[7] . splice @array, 8, 1;
    Your method: 1 2 3 4 5 6 7 89 9 10 Splice method: 1 2 3 4 5 6 7 89 10
      On splice; the third index tells perl how many elements to remove. Thus this effectively does what you want

      Just want to add to the lineup above that after the splice, index 8 still exists and now holds value 10 and so on (whereas previously index n held value n+1, it now holds n+2 for n = 8..15

      Or am I just too tired? :P

        Or am I just too tired? :P

        I think so.

        What would you expect to happen with the indices, if you insert elements into the Array (fourth Parameter of splice)?

Re: Concatenating Array elements
by Laurent_R (Canon) on Aug 19, 2014 at 21:13 UTC
    The splice function is one good way to go, you could also rebuild your array using array slices:
    $ perl -e 'my @a = (0..15); @a = (@a[0..7], $a[8].$a[9], @a[10..15]); +print "@a \n";' 0 1 2 3 4 5 6 7 89 10 11 12 13 14 15
Re: Concatenating Array elements
by lmtaylor (Novice) on Aug 20, 2014 at 19:27 UTC

    Wow, thank you all for the help. Sorry about the indices error, I promise, I do know they start at 0, I just wrote this code up quickly for an example and wasn't thinking. Sorry!

    I will work with the splice function, since I do want to remove the element being joined with the previous element. My problem was figuring out how to iterate the index numbers because I wasn't sure if they would change or not after the element has been taken out. Thank you for you help!