合并两个 yml 文件不处理重复项?
Merge two yml files does not handle duplicates?
我正在尝试使用 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
.
的数组引用
那么像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: [=10=] 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
.
最后,不像上面那样手动处理天真的 merge
的结果,可以使用 Hash::Merge::add_behavior_spec and then have the module do it all. For specific examples of how to use this feature see for instance 编写所需的行为代码
和 this post and .
请注意,在这种情况下,您仍需编写所有代码来完成上述工作,但该模块确实让您无需动手操作一些技巧。
我正在尝试使用 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
.
那么像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: [=10=] 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
.
最后,不像上面那样手动处理天真的 merge
的结果,可以使用 Hash::Merge::add_behavior_spec and then have the module do it all. For specific examples of how to use this feature see for instance
请注意,在这种情况下,您仍需编写所有代码来完成上述工作,但该模块确实让您无需动手操作一些技巧。