What are the operations allowed on array, while iterating through it? Is it possible to shift/unshift, pop/push, delete elements without confusing the iterator?
Is that any different for adding/removing key-value pair from hash?
Thank you for your help.
You can assign to existing elements, but should not add or remove them. So no shift, unshift, pop, push, or splice. perlsyn:
If any part of LIST is an array, foreach will get very confused if you add or remove elements within the loop body, for example with splice. So don't do that.
If you are iterating over a hash with each
, you should also avoid adding or removing elements, except that you are explicitly allowed to remove the current element. each:
If you add or delete a hash's elements while iterating over it, the effect on the iterator is unspecified; for example, entries may be skipped or duplicated--so don't do that. Exception: It is always safe to delete the item most recently returned by each(), so the following code works properly:
But as it says, the worst that could happen is entries being skipped or duplicated; modifying an array you are looping over, on the other hand, can lead to segfaults.
As ysth has already pointed out, it is unwise to attempt to modify an array while iterating directly on its elements.
However, if one does want to modify an array dependent on the element values, the trick is to do it in reverse index order.
For example, say I have an array of numbers. I would like modifier the array so that every multiple of 4 has a string inserted after it, and every multiple of 5 is removed. I would accomplish that 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 transform an array, it's also possible to use map
like so:
my @newarray = map {
( ( ($_) x !!( $_ % 5 ) ), # Remove multiples of 5
( ('insert') x !( $_ % 4 ) ), # Insert After multiples of 4
)
} ( 1 .. 20 );
use Data::Dump;
dd @newarray;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With