in reply to Reversing Hash

Hi Dave
That doesn't work:
Your script gives me answer without any 'reduction' in rev_hash keys.
$rev_hash{1 20 3} = "key1"
$rev_hash{1 9 17} = "key4 key5"
$rev_hash{1 9 8} = "key3"
$rev_hash{1 30 4 7} = "key2"
Which doesn't reduce the keys to its minimum possible. I like to have keys "3" "1 17" "1 8" and "4" . so the answer should be
$rev_hash{3} = "key1"
$rev_hash{1 17} = "key4 key5"
$rev_hash{1 8} = "key3"
$rev_hash{4} = "key2"

Thanks
artist

Update: I think question is mis-understood by most first-answeres. Above example would make it clear.

Update2: Hofmator gave a more correct solution at Re: Re: Re: Reversing Hash as it reduces most elements in total. I overlooked that earlier and should have produced a better example.

Replies are listed 'Best First'.
Re^2: Reversing Hash
by Aristotle (Chancellor) on Mar 03, 2003 at 14:30 UTC
    You'll have to do that in three steps. First step:
    my %hash = ( 'key1' => [1, 20, 3], 'key2' => [1, 30, 4, 7], 'key3' => [1, 9, 8], 'key4' => [1, 9, 17], 'key5' => [1, 9, 17], ); my %rev_hash; while(my ($k, $v) = each %hash) { push @{$rev_hash{$_}}, $k for @$v; }
    Now we have this:
    %rev_hash = (
    	'7'  => ['key2'],
    	'8'  => ['key3'],
    	'30' => ['key2'],
    	'9'  => [ 'key3', 'key4', 'key5' ],
    	'1'  => [ 'key1', 'key2', 'key3', 'key4', 'key5' ],
    	'17' => [ 'key4', 'key5' ],
    	'3'  => ['key1'],
    	'4'  => ['key2'],
    	'20' => ['key1']
    );
    Now let's lump together unique lists of values. I tried a more general approach trying to compare arrays as arrays at first, but it makes things much harder due to double bookkeeping. Since you just want the values concatenated to a string, the approach can be simplified drastically by doing that beforehand.
    $_ = join ' ', sort @$_ for values %rev_hash; my %inv_hash; while(my ($k, $v) = each %rev_hash) { push @{$inv_hash{$v}}, $k; }
    Almost all the way there:
    %inv_hash = (
    	'key1'                     => [ '3', '20' ],
    	'key3 key4 key5'           => ['9'],
    	'key2'                     => [ '7', '30', '4' ],
    	'key3'                     => ['8'],
    	'key4 key5'                => ['17'],
    	'key1 key2 key3 key4 key5' => ['1'],
    );
    We need to concatenate and reverse one final time:
    $_ = join ' ', sort {$a<=>$b} @$_ for values %inv_hash; my %revinv_hash = reverse %inv_hash;
    And now we have:
    %revinv_hash = (
    	'3 20'   => 'key1',
    	'8'      => 'key3',
    	'9'      => 'key3 key4 key5',
    	'1'      => 'key1 key2 key3 key4 key5',
    	'17'     => 'key4 key5',
    	'4 7 30' => 'key2'
    );
    There you go.

    Makeshifts last the longest.