【问题标题】:FInd overlapping values in two HoA查找两个 HoA 中的重叠值
【发布时间】:2013-09-08 04:22:38
【问题描述】:

我有两个 HoA,每个都包含 2 个数组作为值。下面的代码先按照key对第一个HoA进行排序,如果key相同,则按照第一个数组的对应值:

#!/usr/bin/perl
use warnings;
use strict;
use Data::Dumper;
$Data::Dumper::Sortkeys = 1;

my @array1 = qw (1 1 1 4 5); # Note '1' appears several times
my @array2 = qw (10 45 2 1 6);
my @array3 = qw (a b c d e);

my %hash1;   
push @{$hash1{$array1[$_]}}, [ $array2[$_], $array3[$_] ] for 0 .. $#array1;

my @arrayA = qw (2 5 1 0 4); 
my @arrayB = qw (1 3 6 0 7); 
my @arrayC = qw (a z v i d);

my %hash2;   
push @{$hash2{$arrayA[$_]}}, [ $arrayB[$_], $arrayC[$_]] for 0 .. $#arrayA;

for my $key (sort keys %hash1) { 
    for my $value (sort { $a->[0] <=> $b->[0] } @{ $hash1{$key} } ) {
        my ($arr2, $arr3) = @$value;
        print "$key: $arr2\t$arr3\n";
    }
}

我希望能够执行上述功能,但另外比较(例如@array3和@arrayC之间的值。如果两个数组中都存在一个值,那么我想跳过它,并打印出每个数组的键和值该数组的“唯一”行。

hash1 和 hash2 的输出(就目前而言),用 * 表示的值之间有重叠:

哈希1

1: 2    c
1: 10   a *
1: 45   b
4: 1    d *
5: 6    e

哈希2

0: 0    i
1: 6    v
2: 1    a *
4: 7    d *
5: 3    z

期望的输出: (删除了包含 array3 和 arrayC 匹配元素的行)

0: 0    i
1: 2    c
1: 6    v
1: 45   b
5: 3    z
5: 6    e

即删除:

1: 10   a
4: 1    d

来自第一个哈希,并且:

2: 1    a
4: 7    d

从第二个

如果我要比较键,我会使用:

for my $key (sort keys %hash1) {
    if (exists $hash1{$key}) {
    next;
    }
}

如果我要比较两个数组,我会使用:

foreach (@array3) {
    if ($_~~ @arrayC) {
        next;
    }
}

如何在 HoAs 中实现相同的值?

【问题讨论】:

    标签: arrays perl hash multidimensional-array


    【解决方案1】:

    因为您希望输出从两​​个哈希中排序,我建议您将它们合并。在该过程中,您还可以丢弃没有唯一键的值。

    为了按预期工作,我们应该创建一组出现在两个哈希中的最后一个值项。

    use List::MoreUtils 'uniq';
    
    # build a hash of all common values for the last col, i.e.
    # uniq $hash->{*}[*][1], where `*` would be a slice
    my %last_col;
    for my $hash (\%hash1, \%hash2) {
      $last_col{$_}++ for uniq map $_->[1], map @$_, values %$hash;
    }
    $last_col{$_} < 2 and delete $last_col{$_} for keys %last_col;
    

    我们在那里所做的相当于最后一列值的集合的交集。 现在我们可以合并两个散列,当最后一个列出现时跳过。

    my %merged;
    for my $hash (\%hash1, \%hash2) {
      for my $key (keys %$hash) {
        push @{ $merged{$key} }, grep {not exists $last_col{$_->[1]} } @{ $hash->{$key} };
      }
    }
    

    现在所有的值都被合并了,让我们把它们打印出来:

    for my $key (sort { $a <=> $b } keys %merged) {
      for my $value (sort {$a->[0] <=> $b->[0]}  @{ $merged{$key} }) {
        printf "%s: %s\n", $key, join "\t", @$value;
      }
    }
    

    输出:

    0: 0    i
    1: 2    c
    1: 6    v
    1: 45   b
    5: 3    z
    5: 6    e
    

    确切地说,这个可以在没有显式合并的情况下完成,但这会使代码变得不必要地复杂。

    【讨论】:

    • 感谢您的回答 - 我会试一试,让您知道。从您的角度来看 - 我是否使用正确的数据结构来实现我想要实现的目标?
    • @FlyingFrog 是的,你的数据结构没问题,虽然我会考虑在类中封装一些操作。
    猜你喜欢
    • 1970-01-01
    • 2018-09-29
    • 2010-12-05
    • 1970-01-01
    • 2016-01-21
    • 2013-07-01
    • 2013-08-06
    • 2021-10-25
    • 1970-01-01
    相关资源
    最近更新 更多