perl - 合并两个 yml 文件不处理重复项?

标签 perl yaml perl-data-structures

我正在尝试使用 Hash::Merge perl 模块合并 2 个 yml 文件。并尝试使用 YMAL 模块中的 Dump 将其转储到 yml 文件。

use strict;
use warnings;
use Hash::Merge qw( merge );
Hash::Merge::set_behavior('RETAINMENT_PRECEDENT');
use File::Slurp qw(write_file);
use YAML;
my $yaml1 = $ARGV[0];
my $yaml2 = $ARGV[1];
my $yaml_output = $ARGV[2];
my $clkgrps = &YAML::LoadFile($yaml1);
my $clkgrps1 = &YAML::LoadFile($yaml2);
my $clockgroups = merge($clkgrps1, $clkgrps);
my $out_yaml = Dump $clockgroups;
write_file($yaml_output, { binmode => ':raw' }, $out_yaml);

合并 yml 文件后,我可以看到重复的条目,即两个 yml 文件中的以下内容相同。合并时,它将它们视为不同的条目。我们有什么隐式的方法来处理重复项吗?

最佳答案

从 YAML 文件中获取的数据结构通常包含键,值是 arrayrefs 和 hashrefs。在您的测试用例中,这是键 test 的 arrayref。

那么像Hash::Merge这样的工具只能将hashrefs添加到属于同一key的arrayref;它并不是为了比较数组元素,因为没有通用标准。因此,您需要自己执行此操作以删除重复项,或将您选择的任何特定规则应用于数据。

处理这个问题的一种方法是序列化(因此字符串化)每个可能包含重复项的 arrayref 中的复杂数据结构,以便能够以它们作为键构建哈希,这是处理重复项的标准方法(使用 O( 1)复杂性,尽管可能有一个很大的常数)。

在 Perl 中序列化数据有多种方法。我推荐JSON::XS ,作为一个非常快速的工具,其输出可以被任何语言和工具使用。 (但是当然请研究其他人,这可能更适合您的具体需求。)

使用您的测试用例的简单完整示例

use strict;
use warnings;
use feature 'say';
use Data::Dump qw(dd pp);

use YAML;
use JSON::XS;
use Hash::Merge qw( merge );
#Hash::Merge::set_behavior('RETAINMENT_PRECEDENT');  # irrelevant here

die "Usage: $0 in-file1 in-file2 output-file\n" if @ARGV != 3;

my ($yaml1, $yaml2, $yaml_out) = @ARGV;

my $hr1 = YAML::LoadFile($yaml1);
my $hr2 = YAML::LoadFile($yaml2);
my $merged = merge($hr2, $hr1);
#say "merged: ", pp $merged;

for my $key (keys %$merged) {
    # The same keys get overwritten
    my %uniq = map { encode_json $_ => 1 } @{$merged->{$key}};
    
    # Overwrite the arrayref with the one without dupes
    $merged->{$key} = [ map { decode_json $_ } keys %uniq ];
}
dd $merged;

# Save the final structure...

更复杂的数据结构需要更明智的遍历;考虑使用工具来实现这一点。

使用打印问题中所示的文件

{
  test => [
    { directory => "LIB_DIR", name => "ObsSel.ktc", project => "TOT" },
    { directory => "MODEL_DIR", name => "pipe.v", project => "TOT" },
    {
      directory => "PCIE_LIB_DIR",
      name => "pciechip.ktc",
      project => "PCIE_MODE",
    },
    { directory => "NAME_DIR", name => "fame.v", project => "SINGH" },
    { directory => "TREE_PROJECT", name => "Syn.yml", project => "TOT" },
  ],
}

(我使用 Data::Dump 来显示复杂数据,因为它简单且默认紧凑输出。)

如果序列化和比较整个结构存在问题,请考虑使用某种摘要(校验和、散列)。

另一个选择是按原样比较数据结构,以便手动解决重复项。为了比较复杂的数据结构,我喜欢使用 Test::More,它非常适合任何测试之外的单纯比较。当然,也有专用工具,例如 Data::Compare


最后,我们可以使用 Hash::Merge::add_behavior_spec 编写所需的行为,而不是像上面那样手动处理天真的合并的结果。然后让模块完成这一切。有关如何使用此功能的具体示例,请参阅例如 this postthis postthis post .

请注意,在这种情况下,您仍然需要编写所有代码来完成上面的工作,但该模块确实使您摆脱了一些机制。

关于perl - 合并两个 yml 文件不处理重复项?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67605179/

相关文章:

python - perl 的哈希和 python 的字典之间的区别

php - 使用 symfony4 和 doctrine 设置多个数据库时如何修复在两个数据库上运行的迁移

python - Python 中的 Yaml 合并

perl - perl 中的 print @array 和 print "@array"有什么区别?

perl - 在 Perl 中实现函数式编程

Perl:对其他散列使用引用 has

perl - 双箭头 (=>) 运算符在 Perl 中如何工作?

arrays - 从数组中的元素创建组合

perl - Grep -> 如何替换文本文件的内容

YAML 多行换行,不带空格