Попытка изменить исходный массив в процессе выполнения оператора
опубликован: 2024-09-25 18:40
последняя редакция: 2024-09-25 18:52

Различия в поведении for, map и grep

Сразу оговорюсь, что изменение исходного массива в процессе выполнения цикла - не самая удачная идея. Тем не менее, для исследования поведения языковых конструкций в перле.. в общем, нам никто не может этого запретить.
Итак, довольно стандартная задача: заполнить массив @bbb из элементов массива @aaa по какому-нибудь условию.
Казалось бы, выбор между циклом for, либо map, либо grep - чисто вкусовщина.
Разница оказалась в том, что в процессе цикла for мы можем на ходу изменить исходный массив (а значит - и выходной), а в map/grep - нет. Он там конечно поменяется, но только задним числом.
Я набросал пример, для иллюстрации этого утверждения:
#!/usr/bin/perl
use strict;
use warnings;

sub print_result {
    my ($aaa, $bbb) = @_;
    local $, = ', ';
    print 'aaa: ';
    print @$aaa;
    print "\nbbb: ";
    print @$bbb;
}

my @aaa = (1,2,3);
my @bbb = ();

@bbb = grep { push @aaa, 4 if $_ == 3; $_ } @aaa;
print_result(\@aaa, \@bbb);

print "\n=================\n";

@aaa = (1,2,3);
@bbb = ();

map { push @aaa, 4 if $_ == 3; push @bbb, $_ } @aaa;
print_result(\@aaa, \@bbb);

print "\n=================\n";

@aaa = (1,2,3);
@bbb = ();

for (@aaa) {
    push @aaa, 4 if $_ == 3;
    push @bbb, $_;
}
print_result(\@aaa, \@bbb);


Помимо абстрактного знания, мы ещё и получаем важный вывод: операторы map/grep сразу "резервируют" весь массив под свою задачу, а оператор for - считывает его поэлементно. С точки зрения работы с памятью (для очень больших массивов), поведение оператора for более экономно.