0

Consider this array:

my @array = (hashref1, hashref2, hashref3, hashref1);

How can I remove the duplicate reference hashref1?

2
  • The tricky part about the solution is the fact that you cannot use a reference as hash key. Commented Aug 1, 2023 at 7:19
  • You can use a hash reference as a key, but it will be stringified. You'd use the reference as both the key and value, and takes the values. The hash is inappropriate though if you want to preserve order. Commented Aug 1, 2023 at 21:30

2 Answers 2

3

If by "duplicate reference" you mean they both refer to the same anonymous hash, you can use List::Util's uniq:

#!/usr/bin/perl
use warnings;
use strict;

use List::Util qw{ uniq };
use Data::Dumper;

my $hashref1 = {a => 10};
my $hashref2 = {b => 11};
my $hashref3 = {c => 12};

my @array = ($hashref1, $hashref2, $hashref3, $hashref1);

print Dumper(uniq(@array));

Output:

$VAR1 = {
          'a' => 10
        };
$VAR2 = {
          'b' => 11
        };
$VAR3 = {
          'c' => 12
        };

The stringified versions of the references will be used for comparison, i.e. something like HASH(0x560ee5fdf220). The same references have the same address.

But, if you mean they refer to different objects with the same contents, you need to find a way how to stringify the hashrefs so that the contents is always the same.

#!/usr/bin/perl
use warnings;
use strict;

use List::Util qw{ uniq };
use Data::Dumper;

my $hashref1 = {a => 10, A => 2};
my $hashref2 = {b => 11, B => 3};
my $hashref3 = {c => 12, C => 4};
my $hashref4 = {a => 10, A => 2};

my @array = ($hashref1, $hashref2, $hashref3, $hashref4);

my @serialized = do {
    # Comment out the following line to see how 1 and 4
    # can be different sometimes.
    local $Data::Dumper::Sortkeys = 1;
    map Dumper($_), @array;
};
my $VAR1;
print Dumper(map eval, uniq(@serialized));
Sign up to request clarification or add additional context in comments.

Comments

0

perlfaq4 has How can I remove duplicate elements from a list or array?. In the grep method, it doesn't matter that they are hash references because references pointing to the same data will stringify to the same thing (something like HASH(0x12345678):

use v5.10;
use Data::Dumper;

my $hashref_1 = { one => 1 };
my $hashref_2 = { two => 2 };
my $hashref_3 = { tre => 3 };

my @array = ( $hashref_1, $hashref_2, $hashref_3, $hashref_1);
say Dumper( \@array );

{
my %Seen;
@array = grep { ! $Seen{$_}++ } @array;
};

say Dumper( \@array );

The output shows @array before and after the grep. Notice that in the first bit of Dumper output it knows that the last element is the same as the first, so it references that ($VAR1->[0]):

$VAR1 = [
          {
            'one' => 1
          },
          {
            'two' => 2
          },
          {
            'tre' => 3
          },
          $VAR1->[0]
        ];

$VAR1 = [
          {
            'one' => 1
          },
          {
            'two' => 2
          },
          {
            'tre' => 3
          }
        ];

Now try this when the fourth hash ref has the same key and value as the first hash ref, but is a separate hash:

use v5.10;
use Data::Dumper;

my $hashref_1 = { one => 1 };
my $hashref_2 = { two => 2 };
my $hashref_3 = { tre => 3 };
my $hashref_4 = { one => 1 };  # only looks like $hashref_1

my @array = ( $hashref_1, $hashref_2, $hashref_3, $hashref_4 );
say Dumper( \@array );

{
my %Seen;
@array = grep { ! $Seen{$_}++ } @array;
};

say Dumper( \@array );

Now the array is the same before and after because no reference is repeated. Each reference points to different data:

$VAR1 = [
          {
            'one' => 1
          },
          {
            'two' => 2
          },
          {
            'tre' => 3
          },
          {
            'one' => 1
          }
        ];

$VAR1 = [
          {
            'one' => 1
          },
          {
            'two' => 2
          },
          {
            'tre' => 3
          },
          {
            'one' => 1
          }
        ];

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.