Найти разницу между двумя вложенными хешами perl - PullRequest
2 голосов
/ 14 мая 2019

Я пытаюсь найти разницу в двух файлах, которые содержат записи ключ / значение, и вернуть то, что все ключи / значения добавлены или удалены.В настоящее время я использую linux diff для нахождения разницы, но вполне естественно, что если значения порядков будут изменены, то это будет действительный diff, но я не хочу их перечислять, потому что для меня это недопустимый.

file1:

key1    kamal1.google.com kamal2.google.com kamal3.google.com 
key2    kamal4.google.com 

file2:

key1    kamal1.google.com kamal6.google.com kamal3.google.com 
key3    kamal4.google.com

Что мне нужно:

  • Показать deleted key2 with values kamal4.google.com, added key3 with kamal4.google.com, deleted kamal2.google.com from key1, added kamal6.google.com to key1
  • Сообщение является репрезентативным, мы можем изменить его на более значимое

Какой у меня подход:

  • читать файлы и ставить в разные хеши key1 => {kamal1.google.com => 1, ...}, key2 => {kamal4.google.com => 1}.Я также взял массив в качестве хэша, чтобы мы могли эффективно выполнять различие.
  • Переходим по ключам обоих хэшей и определяем, существует ли он в каком хэше.
  • Сделайте рекурсивный вызов, чтобы найти разностьв значениях (потому что это снова хеш)

Проблема с моим кодом:
- Не работает для вложения
- Потерянная дорожка родителя.

код:

my $file1 = 'file1';
my $file2 = 'file2';

my $old = hashifyFile($file1);
my $new = hashifyFile($file2);
my $result = {};
compareHashes($old , $new, $result);
print Dumper $result;

    sub compareHashes {
        my ($hash1, $hash2, $result) = @_;

            for my $key (keys %$hash1, keys %$hash2) {
                if (not exists $hash2->{$key}) {
                        push @{$result->{deleted}->{$key}}, keys %{$hash1->{$key}};
                } elsif (not exists $hash1->{$key}) {
                        push @{$result->{added}->{$key}}, keys %{$hash2->{$key}};
                } elsif (ref $hash1->{$key} eq 'HASH' or ref $hash2->{$key} eq 'HASH' ) {
                    compareHashes($hash1->{$key}, $hash2->{$key}, $result);
                }
            }
    }

# helper functions
sub trim {
   my $val = shift;
   $val =~ s/^\s*|\s*$//g;
   return $val;
}


sub hashifyFile {
    my $file = shift;
    my $contents = {};
    open my $file_fh, '<', $file or die "couldn't open $file $!";

    my ($key, @val);
    while (my $line = <$file_fh>) {
        # skip blank lines and comments
        next if $line =~ /^\s*$/;
        next if $line =~ /^#/;
        # print "$. $line";

        # if line starts with a word, means its "key values"
        # if it starts with multiple spaces assuming minimum 4, seems values for the previous key
        if ($line =~ /^\w/) {
            ($key, @val) = split /\s+|=/, $line;
        } elsif ($line =~ /^\s{4,}\w/) {
            push @val, split /\s+/, $line;
        }
        my %temp_hash;
        for (@val) {
                # next unless $_;
                $temp_hash{trim($_)} = 1 if trim($_);
        }
        $key = trim($key);
        $contents->{$key} = \%temp_hash if defined $key;

    }

    close $file_fh;
    return $contents;
}

Ответы [ 2 ]

1 голос
/ 14 мая 2019

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

1 голос
/ 14 мая 2019

Вот пример того, как вы можете сделать это на основе вашего описания.Уточните, если это то, что вы хотели.

sub compareHashes {
    my ($hash1, $hash2, $result, $parent) = @_;

    my %all_keys = map {$_ => 1} keys %$hash1, keys %$hash2;

    for my $key (keys %all_keys) {
        if (not exists $hash2->{$key}) {
            if ( defined $parent ) {
                push @{$result->{deleted}->{$parent}}, $key;
            }
            else {
                push @{$result->{deleted}->{$key}}, keys %{$hash1->{$key}};
            }
        } elsif (not exists $hash1->{$key}) {
            if ( defined $parent ) {
                push @{$result->{added}->{$parent}}, $key;
            }
            else {
                push @{$result->{added}->{$key}}, keys %{$hash2->{$key}};
            }
        }
        else {
            if ((ref $hash1->{$key} eq 'HASH') and (ref $hash2->{$key} eq 'HASH') ) {
                compareHashes($hash1->{$key}, $hash2->{$key}, $result, $key);
            }
        }
    }
}

Вывод :

$VAR1 = {
          'added' => {
                       'key3' => [
                                   'kamal4.google.com'
                                 ],
                       'key1' => [
                                   'kamal6.google.com'
                                 ]
                     },
          'deleted' => {
                         'key2' => [
                                     'kamal4.google.com'
                                   ],
                         'key1' => [
                                     'kamal2.google.com'
                                   ]
                       }
        };
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...