helplakmal
helplakmal

Reputation: 173

how to remove duplicate values and create a new perl hash?

my %hash1 = ( 
               a=>192.168.0.1,
               b=>192.168.0.1,
               c=>192.168.2.2,
               d=>192.168.2.3,
               e=>192.168.3.4,
               f=>192.168.3.4
            );

i have a perl hash like given above. keys are device names and values are ip addresses.How do i create a hash with no duplicate ip addresses (like %hash2) using %hash1? (devices that have same ips are removed)

my %hash2 = ( c=>192.168.2.2, d=>192.168.2.3 );

Upvotes: 3

Views: 1923

Answers (3)

Edward
Edward

Reputation: 486

A solution using the CPAN module List::Pairwise:

use strict;
use warnings;
use List::Pairwise qw( grep_pairwise );
use Data::Dumper;
my %hash1 = (
    a => '192.168.0.1',
    b => '192.168.0.1',
    c => '192.168.2.2',
    d => '192.168.2.3',
    e => '192.168.3.4',
    f => '192.168.3.4'
);  
my %count;
for my $ip ( values %hash1 ) { $count{ $ip }++ }
my %hash2 = grep_pairwise { $count{ $b } == 1 ? ( $a => $b ) : () } %hash1;
print Dumper \%hash2;

It's pretty straightforward. First you count the IPs in an auxiliary hash. And then you select only those IPs with a count of one using grep_pairwise from List::Pairwise. The syntax of grep_pairwise is like grep:

my @result = grep_pairwise { ... } @list;

The idea of grep_pairwise is to select the elements of @list two by two, with $a representing the first element of the pair, and $b the second (in this case the IP). (Remember that a hash evaluates to a list of ($key1, $value1, $key2, $value2, ...) pairs in list context).

Upvotes: 1

Suic
Suic

Reputation: 2501

First of all you need to quote your IP addresses, because 192.168.0.1 is V-String in perl, means chr(192).chr(168).chr(0).chr(1).
And my variant is:

my %t;
$t{$_}++ for values %hash1; #count values
my @keys = grep
               { $t{ $hash1{ $_ } } == 1 }
           keys %hash1; #find keys for slice
my %hash2;
@hash2{ @keys } = @hash1{ @keys }; #hash slice

Upvotes: 6

Toto
Toto

Reputation: 91385

How about:

my %hash1 = (
   a=>'192.168.0.1',
   b=>'192.168.0.1',
   c=>'192.168.2.2',
   d=>'192.168.2.3',
   e=>'192.168.3.4',
   f=>'192.168.3.4',
);
my (%seen, %out);

while( my ($k,$v) = each %hash1) {
    if ($seen{$v}) {
        delete $out{$seen{$v}};
    } else {
        $seen{$v} = $k;
        $out{$k} = $v;
    }
}
say Dumper\%out;

output:

$VAR1 = {
          'c' => '192.168.2.2',
          'd' => '192.168.2.3'
        };

Upvotes: 3

Related Questions