Perl - operations allowed on an array when iterating through it

What operations are allowed for an array iterating through it? Is it possible to nudge / not nudge, pop / click, remove items without confusing the iterator?

Is there something else to add / remove a key-value pair from a hash?

Thank you for your help.

+3


source to share


2 answers


You can assign to existing items, but you must not add or remove them. So no shift, offset, pop, push, or splicing occurs. perlsyn :

If any part of the LIST is an array, foreach will be very confusing if you add or remove elements inside the loop body, for example using splicing. So don't do it.

If you are repeating a hash with each

, you should also avoid adding or removing elements, except that you are explicitly allowed to delete the current element. each :



If you add or remove hash elements while iterating over it, the effect on the iterator is not specified; for example, records can be skipped or duplicated - so don't do that. Exception: It is always safe to delete an item that was recently returned by each (), so the following code works correctly:

But as the saying goes, the worst that can happen is missing or duplicate entries; on the other hand, changing the array you are iterating over can lead to segfaults.

+4


source


As already pointed out by ysth, it is impractical to try to modify an array while iterating directly on its elements.

However, if you want to change the array depending on the values ​​of an element, the trick is to do it in reverse index order.

For example, let's say I have an array of numbers. I would like an array modifier so that every multiple of 4 has a row inserted after it and every multiple of 5 is removed. I would accomplish this using the following:

use strict;
use warnings;

my @array = ( 1 .. 20 );

for my $i ( reverse 0 .. $#array ) {
    # Insert after multiples of 4
    if ( ( $array[$i] % 4 ) == 0 ) {
        splice @array, $i + 1, 0, "insert";
    }

    # Remove multiples of 5
    if ( ( $array[$i] % 5 ) == 0 ) {
        splice @array, $i, 1;
    }
}

use Data::Dump;
dd @array;

      



Outputs:

(
  1 .. 4,
  "insert",
  6,
  7,
  8,
  "insert",
  9,
  11,
  12,
  "insert",
  13,
  14,
  16,
  "insert",
  17,
  18,
  19,
  "insert",
)

      

Alternatively, if you want to convert the array, can also be used map

like this:

my @newarray = map {
    (   ( ($_) x !!( $_ % 5 ) ),         # Remove multiples of 5
        ( ('insert') x !( $_ % 4 ) ),    # Insert After multiples of 4
        )
} ( 1 .. 20 );

use Data::Dump;
dd @newarray;

      

+1


source







All Articles