Perl 合并数组的散列
Perl merge hash of array
我有数字数组的散列,
我想将散列元素与普通数字合并。
例如。
输入哈希
%HoA = (
A1 => [ "1", "2", "3", "4" ],
A2 => [ "5", "6", "7", "8" ],
A3 => [ "1", "9", "10", "11" ],
A4 => [ "12", "13", "14", "10" ],
);
输出哈希
%HoA_output = (
A1 => [ "1", "2", "3", "4", "9", "10", "11", "12", "13", "14" ],
A2 => [ "5", "6", "7", "8" ],
);
我需要一个解决方案,它可以快速评估一个散列,该散列具有近 50k 个键,每个数组中有 8 个数字。
问候
好的,从根本上讲 - 这不是一件容易的事,因为您确实需要相互检查每个元素以查看它们是否存在。我能想到的最好办法是通过合并列表来节省一些精力,并使用索引来跟踪欺骗。
我会这样处理:
use strict;
use warnings;
use Data::Dumper;
my %HoA = (
A1 => [ "1", "2", "3", "4" ],
A2 => [ "5", "6", "7", "8" ],
A3 => [ "1", "9", "10", "11" ],
A4 => [ "12", "13", "14", "10" ],
);
print Dumper \%HoA;
my %found;
sub merge_and_delete {
my ( $first_key, $second_key ) = @_;
print "Merging $first_key with $second_key\n";
#use hash to remove dupes.
my %elements;
foreach my $element ( @{ $HoA{$first_key} }, @{ $HoA{$second_key} } )
{
$elements{$element}++;
#update index - don't want to point it to an array we're deleting
$found{$element} = $first_key;
}
#sorting for neatness - you might want to do a numeric sort instead,
#as by default %HoA contains text elements.
$HoA{$first_key} = [ sort keys %elements ];
delete $HoA{$second_key};
}
foreach my $key ( sort keys %HoA ) {
print "$key\n";
foreach my $element ( sort @{ $HoA{$key} } ) {
if ( $found{$element} ) {
#this element is present in another list, we merge.
print "$element found in $found{$element}\n";
merge_and_delete( $found{$element}, $key );
last;
}
else {
#add this unique match to our index
print "$element -> $key\n";
$found{$element} = $key;
}
}
}
print Dumper \%HoA;
您迭代 %HoA
上的每个元素,并创建一个索引 table %found
。这个索引 table 你用来检测一个元素是否已经被看到,然后触发一个 merge
- 然后重建索引。不过,您可能需要注意大型数据集的内存消耗,因为您的索引可以增长到几乎与原始数据集一样大(如果存在足够的唯一元素)。
但是因为我们停止处理第一个匹配项,所以我们不再需要检查 every 个键,并且因为我们丢弃合并的数组并更新索引,所以我们不再需要进行全面比较。
这本质上是一个图形问题,您要在其中确定未连接分量的集合
此解决方案使用 Graph::Undirected::Components
模块,其唯一目的就是做到这一点。希望它对你的扩展数据集足够快,但你比我更容易确定
该程序创建一个图形,并将数据中每个键的边(连接)添加到其值的每个元素。然后,调用 connected_components
returns 所有相互连接的不同节点集——包括键和值——
最终的 for
循环使用 List::MoreUtils
中的 part
再次从值中过滤键,基于节点值是否作为原始哈希数据中的键出现。 (如果任何键值也可以出现在值中,您将不得不调整它。)然后第一个键和排序的值项一起用于在 %result
散列
use strict;
use warnings;
use Graph::Undirected::Components;
use List::Util 'minstr';
use List::MoreUtils 'part';
my %data = (
A1 => [ 1, 2, 3, 4 ],
A2 => [ 5, 6, 7, 8 ],
A3 => [ 1, 9, 10, 11 ],
A4 => [ 12, 13, 14, 10 ],
);
my $graph = Graph::Undirected::Components->new;
while ( my ($k, $v) = each %data ) {
$graph->add_edge($k, $_) for @$v;
}
my %result;
for my $component ( $graph->connected_components ) {
my @keys_vals = part { $data{$_} ? 0 : 1 } @$component;
my $key = minstr @{ $keys_vals[0] };
my @values = sort { $a <=> $b } @{ $keys_vals[1] };
$result{$key} = \@values;
}
use Data::Dump;
dd \%result;
输出
{ A1 => [1 .. 4, 9 .. 14], A2 => [5 .. 8] }
我有数字数组的散列,
我想将散列元素与普通数字合并。
例如。 输入哈希
%HoA = (
A1 => [ "1", "2", "3", "4" ],
A2 => [ "5", "6", "7", "8" ],
A3 => [ "1", "9", "10", "11" ],
A4 => [ "12", "13", "14", "10" ],
);
输出哈希
%HoA_output = (
A1 => [ "1", "2", "3", "4", "9", "10", "11", "12", "13", "14" ],
A2 => [ "5", "6", "7", "8" ],
);
我需要一个解决方案,它可以快速评估一个散列,该散列具有近 50k 个键,每个数组中有 8 个数字。
问候
好的,从根本上讲 - 这不是一件容易的事,因为您确实需要相互检查每个元素以查看它们是否存在。我能想到的最好办法是通过合并列表来节省一些精力,并使用索引来跟踪欺骗。
我会这样处理:
use strict;
use warnings;
use Data::Dumper;
my %HoA = (
A1 => [ "1", "2", "3", "4" ],
A2 => [ "5", "6", "7", "8" ],
A3 => [ "1", "9", "10", "11" ],
A4 => [ "12", "13", "14", "10" ],
);
print Dumper \%HoA;
my %found;
sub merge_and_delete {
my ( $first_key, $second_key ) = @_;
print "Merging $first_key with $second_key\n";
#use hash to remove dupes.
my %elements;
foreach my $element ( @{ $HoA{$first_key} }, @{ $HoA{$second_key} } )
{
$elements{$element}++;
#update index - don't want to point it to an array we're deleting
$found{$element} = $first_key;
}
#sorting for neatness - you might want to do a numeric sort instead,
#as by default %HoA contains text elements.
$HoA{$first_key} = [ sort keys %elements ];
delete $HoA{$second_key};
}
foreach my $key ( sort keys %HoA ) {
print "$key\n";
foreach my $element ( sort @{ $HoA{$key} } ) {
if ( $found{$element} ) {
#this element is present in another list, we merge.
print "$element found in $found{$element}\n";
merge_and_delete( $found{$element}, $key );
last;
}
else {
#add this unique match to our index
print "$element -> $key\n";
$found{$element} = $key;
}
}
}
print Dumper \%HoA;
您迭代 %HoA
上的每个元素,并创建一个索引 table %found
。这个索引 table 你用来检测一个元素是否已经被看到,然后触发一个 merge
- 然后重建索引。不过,您可能需要注意大型数据集的内存消耗,因为您的索引可以增长到几乎与原始数据集一样大(如果存在足够的唯一元素)。
但是因为我们停止处理第一个匹配项,所以我们不再需要检查 every 个键,并且因为我们丢弃合并的数组并更新索引,所以我们不再需要进行全面比较。
这本质上是一个图形问题,您要在其中确定未连接分量的集合
此解决方案使用 Graph::Undirected::Components
模块,其唯一目的就是做到这一点。希望它对你的扩展数据集足够快,但你比我更容易确定
该程序创建一个图形,并将数据中每个键的边(连接)添加到其值的每个元素。然后,调用 connected_components
returns 所有相互连接的不同节点集——包括键和值——
最终的 for
循环使用 List::MoreUtils
中的 part
再次从值中过滤键,基于节点值是否作为原始哈希数据中的键出现。 (如果任何键值也可以出现在值中,您将不得不调整它。)然后第一个键和排序的值项一起用于在 %result
散列
use strict;
use warnings;
use Graph::Undirected::Components;
use List::Util 'minstr';
use List::MoreUtils 'part';
my %data = (
A1 => [ 1, 2, 3, 4 ],
A2 => [ 5, 6, 7, 8 ],
A3 => [ 1, 9, 10, 11 ],
A4 => [ 12, 13, 14, 10 ],
);
my $graph = Graph::Undirected::Components->new;
while ( my ($k, $v) = each %data ) {
$graph->add_edge($k, $_) for @$v;
}
my %result;
for my $component ( $graph->connected_components ) {
my @keys_vals = part { $data{$_} ? 0 : 1 } @$component;
my $key = minstr @{ $keys_vals[0] };
my @values = sort { $a <=> $b } @{ $keys_vals[1] };
$result{$key} = \@values;
}
use Data::Dump;
dd \%result;
输出
{ A1 => [1 .. 4, 9 .. 14], A2 => [5 .. 8] }