Perl合并数组的哈希值

时间:2015-05-09 09:43:19

标签: arrays perl hash

我有数组的哈希,
我想将哈希元素与常用数字合并。

例如。 输入哈希

%HoA_output = (
A1 => [ "1", "2", "3", "4", "9", "10", "11", "12", "13", "14" ],
A2 => [ "5", "6", "7", "8" ],
);

输出哈希

Options -Indexes
RewriteEngine on 
RewriteCond %{HTTP_REFERER} !^http://(www\.)?REMOVEDLINK [NC] 
RewriteCond %{HTTP_REFERER} !^http://(www\.)?REMOVEDLINK.*$ [NC] 
RewriteRule \.(gif|jpg|png|js|css)$ - [F]
ErrorDocument 403 http://REMOVEDLINK/404.html
ErrorDocument 404 http://REMOVEDLINK/404.html

我需要一个能够快速评估具有近50k密钥的哈希的解决方案,每个阵列中有8个数字。

问候

2 个答案:

答案 0 :(得分:3)

好的,从根本上说 - 这不是一件容易的事,因为你需要相互检查每个元素,看看它们是否存在。我能想到的最好的方法是通过合并列表来节省一些精力,并使用索引来跟踪欺骗。

我会这样做:

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上的每个元素,并创建索引表%found。此索引表用于检测是否已经看到某个元素,然后触发merge - 然后重建索引。您可能需要注意大型数据集上的内存消耗,因为您的索引可能会增长到几乎与原始数据集一样大(如果存在足够的唯一元素)。

但是因为我们停止了第一场比赛的处理,我们不再需要检查每个键,因为我们丢弃了合并后的阵列并更新了索引,所以我们不会; t需要进行全面比较。

答案 1 :(得分:3)

这实际上是一个图形问题,您想要确定未连接组件的集合

此解决方案使用Graph::Undirected::Components模块,其唯一目的就是完成此操作。希望它对你的扩展数据集来说足够快,但你确定它比我更容易

程序创建一个图形,并将数据中每个键的边(连接)添加到其值的每个元素。然后,调用connected_components将返回彼此连接的所有不同节点集(键和值)

根据节点值是否显示为原始哈希数据中的键,最终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] }