web-dev-qa-db-ja.com

Perlでのハッシュのキーと値の反転

値をキーにし、キーを値にしたいのですが。これを行うための最良の方法は何ですか?

25
Steffan Harris

http://www.dreamincode.net/forums/topic/46400-swap-hash-values/ から適応:

ハッシュが$hashに保存されていると仮定します。

while (($key, $value) = each %hash) {
   $hash2{$value}=$key;
}

%hash=%hash2;

reversehttp://www.misc-Perl-info.com/Perl-)を使用すると、はるかに洗練されたソリューションを実現できるようです。 hashes.html#reverseph ):

%nhash = reverse %hash;

逆にすると、重複する値が上書きされることに注意してください。

21
jsalonen

reverseを使用します:

use Data::Dumper;

my %hash = ('month', 'may', 'year', '2011');
print Dumper \%hash;
%hash = reverse %hash;
print Dumper \%hash;
15
fvox

前述のように、最も単純なのは

my %inverse = reverse %original;

複数の要素が同じ値を持つ場合、「失敗」します。その状況を処理するためのHoAを作成できます。

my %inverse;
Push @{ $inverse{ $original{$_} } }, $_ for keys %original;
11
ikegami

だからあなたはハッシュに逆キーと値が欲しいですか?したがって、リバースを使用してください...;)

%hash2 = reverse %hash;

元に戻す(k1 => v1、k2 => v2)-歩留まり(v2 => k2、v1 => k1)-そしてそれがあなたが望むものです。 ;)

3
jm666
my %orig_hash = (...);
my %new_hash;

%new_hash = map { $orig_hash{$_} => $_ } keys(%orig_hash);
2
snoofkin

Map-over-keysソリューションはより柔軟です。あなたの価値が単純な価値ではない場合はどうなりますか?

my %forward;
my %reverse;

#forward is built such that each key maps to a value that is a hash ref:
#{ a => 'something', b=> 'something else'}

%reverse = map { join(',', @{$_}{qw(a b)}) => $_ } keys %forward;
1
mpersico

_Hash::MultiValue_ を使用してこれを行う方法は次のとおりです。

_use experimental qw(postderef);

sub invert {
  use Hash::MultiValue;
  my $mvh = Hash::MultiValue->from_mixed(shift);

  my $inverted;    
  $mvh->each( sub { Push $inverted->{ $_[1] }->@* , $_[0] } ) ;
  return $inverted;
}
_

これをテストするには、次のことを試してください。

_my %test_hash = (
  q => [qw/1 2 3 4/],
  w => [qw/4 6 5 7/],
  e => ["8"],
  r => ["9"],
  t => ["10"],
  y => ["11"],
);

my $wow  = invert(\%test_hash);
my $wow2 = invert($wow);

use DDP;
print "\n \%test_hash:\n\n" ;
p %test_hash;
print "\n \%test_hash inverted as:\n\n" ;
p $wow ;

# We need to sort the contents of the multi-value array reference
# for the is_deeply() comparison:
map { 
   $test_hash{$_} = [ sort { $a cmp $b || $a <=> $b } @{ $test_hash{$_} } ] 
} keys %test_hash ; 

map { 
   $wow2->{$_} = [ sort { $a cmp $b || $a <=> $b } @{ $wow2->{$_} } ] 
} keys %$wow2 ; 

use Test::More ;
is_deeply(\%test_hash, $wow2, "double inverted hash == original");
done_testing;
_

補遺

ここでギミックテストに合格するために、invert()関数は値として配列参照を持つ_%test_hash_に依存していることに注意してください。ハッシュ値が配列参照でない場合にこれを回避するには、通常/混合ハッシュを複数値ハッシュに「強制」して、_Hash::MultiValue_がオブジェクトに祝福できるようにします。ただし、このアプローチでは、単一の値でも配列参照として表示されます。

_for ( keys %test_hash )  { 
     if ( ref $test_hash{$_} ne 'ARRAY' ) { 
           $test_hash{$_}  = [ $test_hash{$_} ] 
     } 
}
_

これは長い間:

_ref($_) or $_ = [ $_ ] for values %test_hash ;
_

これは、「往復」テストに合格するためにのみ必要です。

0
G. Cito