Я так понимаю, ответ Шона работает для удаления дубликатов, для чего он выглядит хорошо.
Следующая проблема заключается в том, что мы можем получить пустые структуры, которые также должны быть удалены.Но тогда также могут быть структуры, которые содержат только пустые структуры и т. Д., И я предполагаю, что все это необходимо устранить.
Я использую нужный вопрос-hashref из вопроса (из которого я удаляю одну name=>...
, чтобы не было дубликатов) и добавляю некоторые пустые проблемы.
use warnings;
use strict;
use feature 'say';
use Data::Dump qw(dd pp);
my $hr = {
'cat' => 'meow',
'dog' => [
{
'a' => { 'chow' => { 'name' => 'barney' } },
},
{
'b' => { 'lab' => 'betty' },
'c' => 'pebbles'
},
{
'd' => { 'shihtzu' => 'bambam' },
},
{ # all of the following need to go, and this hashref
'e' => { },
'f' => { noval => { } },
'g' => [ { }, { nada => { } }, [ ] ],
},
],
};
dd $hr; say '';
for my $k (sort keys %$hr) {
next_level($hr, $k, $hr->{$k}, 'key');
}
# Takes: data structure (reference), key/index at which it is found,
# its value for it, and description string of which it is, 'key|idx'
sub next_level {
my ($ds, $index, $val, $kind) = @_;
my $type = ref $val;
if ($type eq 'ARRAY') {
for my $i (0..$#$val) {
next_level(
( $kind eq 'key' ? $ds->{$index} : $ds->[$index] ),
$i, $val->[$i], 'idx'
);
}
# Collect indices for and delete elements that are empty
my @to_delete;
for my $i (0..$#$val) {
if ( (ref $val->[$i] eq 'HASH' and not keys %{$val->[$i]}) or
(ref $val->[$i] eq 'ARRAY' and not @{$val->[$i]}) )
{
say "No value/empty for index $i, record for deletion";
push @to_delete, $i;
}
}
if (@to_delete) {
my %ref_idx = map { $_ => 1 } @to_delete;
@$val = @$val[ grep { not exists $ref_idx{$_} } 0..$#$val ];
}
}
elsif ($type eq 'HASH') {
for my $k (sort keys %{$val}) {
my $ds_next_level =
($kind eq 'key') ? $ds->{$index} : $ds->[$index];
next_level( $ds_next_level, $k, $val->{$k}, 'key' );
# Delete if empty
if ( (ref $val->{$k} eq 'HASH' and not keys %{$val->{$k}}) or
(ref $val->{$k} eq 'ARRAY' and not @{$val->{$k}}) )
{
say "No value/empty for key $k, delete";
delete $ds_next_level->{$k}
}
}
}
#elsif (not $type) { say "A value: ", $val }
}
say ''; dd $hr;
Этообычный рекурсивный обход сложной структуры данных, но с изюминкой: для того, чтобы иметь возможность удалять компоненты, рекурсивному подпрограмме также нужна сама структура данных, для которой найден ключ (в хэш-адресе) или индекс (в массиве-ссылки)и какой из двух это был ключ или индекс.
После рекурсии цель удаляется, если она пуста, если она находится в хэш-функции.Сначала проверяется массивная ссылка на все пустые элементы, а затем они удаляются путем перезаписи массивной ссылки, срезом массива, который исключает индексы для элементов, которые содержат только пустые структуры данных.
Для исключения «плохих» индексов для эффективности используется ссылочный хеш.Перезапись массива может быть быстрее при использовании map
(см. в этом посте ), или не может быть, если срезы допускают определенные (интерпретатор) оптимизации.
Вывод
{
cat => "meow",
dog => [
{ a => { chow => { name => "barney" } } },
{ b => { lab => "betty" }, c => "pebbles" },
{ d => { shihtzu => "bambam" } },
{ e => {}, f => { noval => {} }, g => [{}, { nada => {} }, []] },
],
}
No value/empty for key e, delete
No value/empty for key noval, delete
No value/empty for key f, delete
No value/empty for key nada, delete
No value/empty for index 0, record for deletion
No value/empty for index 1, record for deletion
No value/empty for index 2, record for deletion
No value/empty for key g, delete
No value/empty for index 3, record for deletion
{
cat => "meow",
dog => [
{ a => { chow => { name => "barney" } } },
{ b => { lab => "betty" }, c => "pebbles" },
{ d => { shihtzu => "bambam" } },
],
}