复杂的多级哈希,其中一些值是数组而其他值不是,我怎样才能在这种哈希的任何级别删除数组元素重复?
只是简单的哈希示例(实际上它更复杂):
$VAR1 = {
'alpha' => {
'code' => [
{
'x' => 1,
'y' => 2
},
{
'x' => 1,
'y' => 2
}
],
'data' => {
'domestic' => [
{
'a' => 0,
'b' => 5
},
{
'a' => 0,
'b' => 5
}
]
}
}
}
Hash包含不同级别的数组,其中一些包含uniq元素,其中一些包含重复项。有时这样的数组元素本身就是复杂的哈希。
删除任何级别的重复项的正确方法是什么?
答案 0 :(得分:1)
我不是那些没有被客体化的深层物体的粉丝,幸运的是,穆斯内置了强制力,这样你就可以将一个深层物体客观化为魔法。
我有点过火了,但我决定继续前进,只是把它作为自己的练习,尽管我认为我可以'咆哮'一些项目并获得更好的结果,或强迫对Alpha的强制: :无论如何,键入以从必填字段构建结果类。
我不完全喜欢我编码的方式,但我不想花费大量时间,但它适用于你上面的对象。你需要做很多工作才能使它更复杂,你需要将代码分解成不同的类:
Alpha.pm:
package Alpha;
use Moose;
use Moose::Util::TypeConstraints;
subtype 'AlphaCodes',
as 'Alpha::Codes';
subtype 'AlphaData',
as 'Alpha::Data';
coerce 'AlphaCodes',
from 'ArrayRef[HashRef]',
via { Alpha::Codes->new( data => $_ ) };
coerce 'AlphaData',
from 'HashRef',
via { Alpha::Data->new($_) };
has 'code' => (
is => 'ro',
isa => 'AlphaCodes',
required => 1,
coerce => 1);
has 'data' => (
is => 'ro',
isa => 'AlphaData',
required => 1,
coerce => 1);
package Alpha::Codes;
use Moose;
use Moose::Util::TypeConstraints;
extends 'Alpha::KeyedList';
subtype 'ArrayRefOfCodes',
as 'ArrayRef[Alpha::Code]';
coerce 'ArrayRefOfCodes',
from 'ArrayRef[HashRef]',
via { [ map { Alpha::Code->new($_) } @$_ ] };
has 'data' => (
is => 'ro',
isa => 'ArrayRefOfCodes',
required => 1,
coerce => 1);
package Alpha::KeyedList;
use Moose;
use Moose::Util::TypeConstraints;
sub unique_list {
my $self = shift;
my %seen = ();
my @retval = ();
foreach my $item ( @{$self->data} ) {
unless ( $seen{$item->key} ) {
push(@retval,$item);
$seen{$item->key} = 1;
}
}
return @retval;
}
package Alpha::Data;
use Moose;
use Moose::Util::TypeConstraints;
subtype 'AlphaDataDomestics',
as 'Alpha::Data::Domestics';
coerce 'AlphaDataDomestics',
from 'ArrayRef[HashRef]',
via { Alpha::Data::Domestics->new(data => $_) };
has 'domestic' => (
is => 'ro',
isa => 'AlphaDataDomestics',
required => 1,
coerce => 1 );
package Alpha::Data::Domestics;
use Moose;
use Moose::Util::TypeConstraints;
extends 'Alpha::KeyedList';
subtype 'ArrayRefOfDomestics',
as 'ArrayRef[Alpha::Data::Domestic]';
coerce 'ArrayRefOfDomestics',
from 'ArrayRef[HashRef]',
via { [ map { Alpha::Data::Domestic->new($_) } @$_ ] };
has 'data' => (
is => 'ro',
isa => 'ArrayRefOfDomestics',
required => 1,
coerce => 1);
package Alpha::Data::Domestic;
use Moose;
extends 'Alpha::Keyed';
has 'a' => ( is => 'ro' , isa => 'Str' , required => 1 );
has 'b' => ( is => 'ro' , isa => 'Str' , required => 1 );
sub build_key {
my $self= shift;
return $self->a . '__' . $self->b;
}
package Alpha::Code;
use Moose;
extends 'Alpha::Keyed';
has 'x' => ( is => 'ro' , isa => 'Str' , required => 1 );
has 'y' => ( is => 'ro' , isa => 'Str' , required => 1 );
sub build_key {
my $self= shift;
return $self->x . '__' . $self->y;
}
package Alpha::Keyed;
use Moose;
has 'key' => ( is => 'ro'
, isa => 'Str'
, builder => 'build_key'
, lazy => 1 );
package main;
my $VAR1 = {
'alpha' => {
'code' => [
{
'x' => 1,
'y' => 2
},
{
'x' => 1,
'y' => 2
}
],
'data' => {
'domestic' => [
{
'a' => 0,
'b' => 5
},
{
'a' => 0,
'b' => 5
},
{
'a' => 1,
'b' => 2
},
]
}
}
};
my $alpha = Alpha->new($VAR1->{alpha});
use Data::Dumper;
warn Dumper([ $alpha->code->unique_list ]);
warn Dumper([ $alpha->data->domestic->unique_list ]);
1;
现在运行:
$VAR1 = [
bless( {
'y' => 2,
'x' => 1,
'key' => '1__2'
}, 'Alpha::Code' )
];
$VAR1 = [
bless( {
'a' => 0,
'b' => 5,
'key' => '0__5'
}, 'Alpha::Data::Domestic' ),
bless( {
'a' => 1,
'b' => 2,
'key' => '1__2'
}, 'Alpha::Data::Domestic' )
];
答案 1 :(得分:1)
此代码使用Data::Compare
模块,似乎可以满足您的需求。
它以递归方式遍历数据结构,并使用模块中的Compare
函数检查它所涉及的每个数组的重复数据。重复项会在找到时删除。
use strict;
use warnings;
use Data::Compare 'Compare';
my %data = (
alpha => {
code => [{ x => 1, y => 2 }, { x => 1, y => 2 }],
data => { domestic => [{ a => 0, b => 5 }, { a => 0, b => 5 }] },
},
);
process_node(\%data);
use Data::Dump;
dd \%data;
sub process_node {
my ($data) = @_;
if (ref $data eq 'HASH') {
process_node($_) for values %$data;
}
elsif (ref $data eq 'ARRAY') {
my $i = 0;
while ($i < @$data-1) {
my $j = $i + 1;
while ($j < @$data) {
if (Compare(@{$data}[$i,$j])) {
splice @$data, $j, 1;
}
else {
$j++;
}
}
$i++;
}
process_node($_) for @$data;
}
}
<强>输出强>
{
alpha => {
code => [{ x => 1, y => 2 }],
data => { domestic => [{ a => 0, b => 5 }] },
},
}
答案 2 :(得分:0)
我会在这里看到问题的答案:How can I compare arrays in Perl?
使用它你应该能够迭代哈希的所有级别并比较数组级别的数组。您当然需要为每个可能的数组配对执行此操作。
如果您可以更好地为数组分配键,以便识别它们,那么您就不必担心这一点,因为每个键都必须是唯一的。