0

それぞれが値として 2 つの配列を含む 2 つの HoA があります。次のコードは、最初の HoA をそのキーでソートし、キーが同じ場合は、最初の配列の対応する値でソートします。

#!/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 など) の間で値を比較したいと考えています。値が両方の配列に存在する場合は、それをスキップして、各行のキーと値を出力したい 'unique ' その配列に。

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;
    }
}

2 つの配列を比較する場合は、次のように使用します。

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

HoA の値に対して同じことを達成するにはどうすればよいですか?

4

1 に答える 1

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;

そこで行ったことは、最後の列の値のセットの共通部分と同等でした。これで、2 つのハッシュをマージして、最後の列が両方に存在する場合はスキップできます。

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

正確には、これは明示的なマージを行わなくても実行できますが、コードが不必要に複雑になります。

于 2013-09-04T16:06:00.297 に答える