Как я могу заменить значения в глубоко вложенной, но произвольной структуре данных? - PullRequest
1 голос
/ 20 марта 2019

У меня есть произвольная структура данных. Форма обычно схожа в том, что она состоит из массивов и хэшей глубиной около четырех уровней, с примерно двумя-шестью значениями, которые я бы хотел изменить. Типичный пример:

$VAR1 = [
          undef,
          [
            {
              '0' => 'some string'
            }
          ],
          undef,
          [
            undef,
            {
              '1033' => 'another string '
            }
          ]
        ];

Хотя я знаю синтаксис достаточно хорошо, чтобы получить доступ к этим двум значениям и изменить их в этом конкретном примере (или любом другом), от одного использования к другому это изменится так, что жестко закодированные выражения не будут работать.

Такое ощущение, что это должен быть простой саб, который запускается рекурсивно, но как только он обнаруживает, что элемент структуры данных является массивом или хэшем, я не знаю, как передать элемент в следующий рекурсивный вызов по ссылке так что он может быть изменен невременным способом. Следующий код дает сбой рекурсивно (хотя, если он не повторяется, он может изменить поверхностное значение в массиве верхнего уровня, и это изменение останется неизменным):

sub deep_nested_replace {
    my ($d, $string) = @_;

    if (ref($d) eq 'ARRAY') {
        for (my $i=0; $i<scalar @$d; $i++) {
            deep_nested_replace($d->[$i], $string);
        }
    }
    elsif (ref($d) eq 'HASH') {
        foreach my $k (keys %$d) {
            deep_nested_replace($d->{$k}, $string);
        }
    }
    elsif (defined $d) {
        $d = $string;
    }
}

Как мне сделать эту работу? Если это неправильный подход, то какой правильный?

1 Ответ

3 голосов
/ 20 марта 2019

Массив @_ с параметрами функции содержит псевдонимы для скаляров (или иные явные ссылки), переданные функции.Изменения к нему будут влиять на данные вызывающего абонента.То же самое с $_ в grep или map.Это то, что исходит от других языков программирования, с которыми вам иногда нужно быть осторожными.

Однако, делая присваивание от одной скалярной переменной к другой, как в идиоматическом my ($d, $string) = @_, скалярное значение копируется изодна переменная к другой.

Если вы хотите повлиять на скалярное значение, передаваемое функции в вызывающей программе, вы можете напрямую работать с массивом @_ и его элементами.

sub deep_nested_replace {
    my ($d, $string) = @_;

    if (ref($d) eq 'ARRAY') {
        deep_nested_replace($_, $string) for @$d;
    }
    elsif (ref($d) eq 'HASH') {
        deep_nested_replace($_, $string) for values %$d;
    }
    elsif (defined $d) {
        $_[0] = $string;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...