Как объединить два хэша, которые начинаются с разных ключей в Perl? - PullRequest
0 голосов
/ 12 февраля 2020

Я должен хэшировать следующим образом:

my %hash1 = (
    'modules' => {
        'top0' => {
            'instances' => {
                'sub_top' => {
                    'instances' => {
                        'inst2' => 2,
                        'inst0' => 0
                    }
                }
            }
        }
    }
);

my %hash2 = (
    'modules' => {
        'sub_top' => {
            'instances' => {
                'inst0' => 0,
                'inst1' => 1
            }
        }
    }
);                                                                   }

Мне нужно объединить их в один ха sh. Я попытался использовать Ha sh :: Merge, но это работает только в том случае, если я начинаю только с подтопа и далее.

my $merged_hash = merge(\%{$hash1{modules}{top0}{instances}}, \%{$hash2{modules}});

Сброс результирующего $merged_hash дает:

$VAR1 = {
    'sub_top' => {
        'instances' => {
            'inst2' => 2,
            'inst0' => 0,
            'inst1' => 1
        }
    }
};

Но я пропустить верхнюю часть hash1:

'modules' => {
    'top0' => {
        'instances' => {

Желаемое ха sh после слияния должно быть так:

$VAR1 = {
    'modules' => {
        'top0' => {
            'instances' => {
                'sub_top' => {
                    'instances' => {
                        'inst2' => 2,
                        'inst0' => 0,
                        'inst1' => 1
                    }
                }
            }
        }
    }
};

Ответы [ 2 ]

3 голосов
/ 13 февраля 2020

Один из возможных способов объединения хешей по предопределенному ключу. Проверьте, соответствует ли оно вашим ожиданиям.

use strict;
use warnings;
use feature 'say';

use Data::Dumper;

my $debug = 0;

my %hash1 = (
    'modules' => {
        'top0' => {
            'instances' => {
                'sub_top' => {
                    'instances' => {
                        'inst2' => 2,
                        'inst0' => 0
                    }
                }
            }
        }
    }
);

my %hash2 = (
    'modules' => {
        'sub_top' => {
            'instances' => {
                'inst0' => 0,
                'inst1' => 1
            }
        }
    }
); 

my $key = 'sub_top';

mergeOnKey(\%hash1, \%hash2, $key);

say Dumper(\%hash1);

sub mergeOnKey {
    my $h1 = shift;
    my $h2 = shift;
    my $k  = shift;

    my $href1 = find_ref($h1,$k);
    my $href2 = find_ref($h2,$k);

    die 'Hash 1 no key was found' unless $href1;
    die 'Hash 2 no key was found' unless $href2;

    merge($href1,$href2);
}

sub merge {
    my $href1 = shift;
    my $href2 = shift;

    foreach my $key (keys %{$href2}) {
        if( ref $href2->{$key} eq ref {} ) {
            merge($href1->{$key},$href2->{$key});
        } else {
            $href1->{$key} = $href2->{$key} unless defined $href1->{$key};
        }
    }

    say Dumper($href1) if $debug;
}

sub find_ref {
    my $href = shift;
    my $key  = shift;

    while( my($k,$v) = each %{$href} ){
        say Dumper($v) if $debug;
        return $v if $k eq $key;
        return find_ref($v,$key) if ref $v eq 'HASH';
    }

    return 0;
}

Вывод

$VAR1 = {
    'modules' => {
        'top0' => {
            'instances' => {
                'sub_top' => {
                    'instances' => {
                        'inst1' => 1,
                        'inst2' => 2,
                        'inst0' => 0
                    }
                }
            }
        }
    }
};
1 голос
/ 13 февраля 2020

Если вы посмотрите на Синопсис для Ha sh :: Merge , в примере показаны два хэша, которые выглядят практически идентичными по структуре. Хеши, которые вы хотите объединить, могут иметь много общего, но они также имеют существенные различия. Таким образом, я бы ожидал, что вы можете объединить их только там, где их структура достаточно «эквивалентна». Вот самый очевидный способ, которым я могу придумать, чтобы они слились с полученным вами ха sh, который вы указали:

#!/bin/env perl
use strict;
use warnings;
use Test::More;    
use Hash::Merge qw(merge);

my %hash1 = (
    'modules' => {
        'top0' => {
            'instances' => {
                'sub_top' => {
                    'instances' => {
                        'inst2' => 2,
                        'inst0' => 0
                    }
                }
            }
        }
    }
);

my %hash2 = (
    'modules' => {
        'sub_top' => {
            'instances' => {
                'inst0' => 0,
                'inst1' => 1
            }
        }
    }
);

# Merge the desired parts of the structure
$hash1{modules}{top0}{instances} =
  merge( \%{ $hash1{modules}{top0}{instances} }, \%{ $hash2{modules} } );

# Demonstrate that merge worked as desired
my %desired = (
    'modules' => {
        'top0' => {
            'instances' => {
                'sub_top' => {
                    'instances' => {
                        'inst2' => 2,
                        'inst0' => 0,
                        'inst1' => 1
                    }
                }
            }
        }
    }
);

is_deeply( \%hash1, \%desired, 'Desired hash is created' );

done_testing();
...