2013-01-13 46 views
1

有複雜的多層次散列,其中一些值是數組而其他值不是,我怎樣才能在這樣的散列的任何級別刪除數組元素重複?在任何散列級別刪除數組元素重複項?

只需簡單的哈希例子(它實際上是方式更復雜的):

$VAR1 = { 
    'alpha' => { 
    'code' => [ 
     { 
     'x' => 1, 
     'y' => 2 
     }, 
     { 
     'x' => 1, 
     'y' => 2 
     } 
    ], 
    'data' => { 
     'domestic' => [ 
     { 
      'a' => 0, 
      'b' => 5 
     }, 
     { 
      'a' => 0, 
      'b' => 5 
     } 
     ] 
    } 
    } 
} 

哈希包含在不同水平陣列和它們中的一些具有uniq的元件,它們中的一些包含重複。有時候這種數組元素本身就是複雜的散列。

什麼是正確的方式來刪除在任何級別的任何大小的重複

+0

對於alpha.code的條目,你知道這些條目總是有 'X' 和 'Y' 的元素,或者說下alpha.data。國內,他們會一直有'一'和'B'? – Horus

+0

@Horus - 結構對於特定數組的每個元素都是相同的... –

+0

基於此,我生成了一個OO響應,您可能想要查看它。你也可以在其上進行Data :: Compare比較。我更喜歡OO版本,因爲我認爲複雜深度的對象不應該表示爲非模式化的hashrefs&arrayrefs。 – Horus

回答

0

我會看到這個問題的答案在這裏:How can I compare arrays in Perl?

使用,你應該能夠通過你的哈希各級迭代,並在陣列級別比較陣列。你當然需要爲每個可能的數組配對做這件事。

如果您可以更好地將密鑰分配給您的陣列,以便它能夠識別它們,那麼您不必擔心這一點,因爲每個密鑰都必須是唯一的。

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') 
    ]; 
+0

+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 }] }, 
    }, 
} 
+0

即使從簡短的角度來看,這個代碼看起來不錯,模塊'Data :: Compare'在'Compare.pm'行'189'變量類型'JSON :: XS :: Boolean'上崩潰了, –