Perl доступ / изменение глубокого хэша по списку массивов - PullRequest
3 голосов
/ 27 августа 2010

Я хочу удалить элемент хэша (любой глубины), который имеет первый ключ как $key[0], второй ключ как $key[1] и т. Д. До тех пор, пока не завершится @key.

ДляНапример, если @key=(23,56,78), то я хочу манипулировать $hash{23}{56}{78}.
. Я не знаю заранее, сколько элементов @key имеет.

Я пытался использовать следующее:

my %the_path;
my $temp=\%the_path;
for(my $cline=0;$cline<=$#keys;$cline++){
     my $cfolder=$keys[$cline];
     $temp->{$cfolder}={};
     $temp=$temp->{$cfolder};
}

Но я не уверен, как манипулировать элементом здесь.Как мне это сделать?

Ответы [ 3 ]

5 голосов
/ 27 августа 2010

Данные :: Diver существует именно для этой цели.

my $last_hash = Data::Diver::Dive( \%hash, @keys[0..$#keys-1] );
if ($last_hash) { delete $last_hash->{ $keys[-1] } }
1 голос
/ 27 августа 2010

Вот пример с рекурсией:

use strict;
use warnings;

my $hash = { foo => { here => 'there', bar => { baz => 100 } } };

## mutates input
sub delete_hash {
  my ( $hash, $keys ) = @_;
  my $key = shift @$keys;
  die "Stopped recursing $key doesn't exist"
    unless exists $hash->{$key}
  ;
  scalar @$keys
    ? delete_hash( $hash->{$key}, $keys )
    : delete $hash->{$key}
  ;
}

delete_hash( $hash, [qw/foo bar/] );

use XXX;
YYY $hash;

Стек действительно растет, а вызовы функций имеют цену.Вы можете явно уменьшить это с помощью версии TCO на Perl с этим кодом:

if (scalar @$keys) {
  @_=($hash->{$key}, $keys);
  goto &delete_hash;
}
else {
  delete $hash->{$key}
}

И также следует отметить, что ни один из этого кода не удаляет дерево: если вы удалите [qw/foo bar baz/], тогда bar будетпустой хэш ref.

foo:
  bar: {}
  here: there
1 голос
/ 27 августа 2010

Вам необходимо пройти вниз по дереву хеш-ссылок, используя следующее значение ключа в списке в качестве ключа для перехода, пока вы не нажмете второй до последнего ключ в списке; затем удалите значение hashref, связанное с последним ключом.

my $hash_ptr = $my_hash_ref;
foreach my $key_num (0..$#keys) {
    my $key = $keys[$key_num];
    if (exists $hash_ptr->{$key}) {
        if ($key_num == $#keys) {
            delete $hash_ptr->{$key};
        } else {
            $hash_ptr = $hash_ptr->{$key}; # Go down 1 level
        }
    } else {
        last;
    }
}

Примечание: это НЕ удаляет какие-либо элементы дерева хеширования выше последнего, даже если они больше не содержат ключей. Другими словами, он удаляет 1 узел, а НЕ весь путь - он, по словам Эвана, не обрезает дерево. Если вы не это имели в виду, уточните.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...