3

I have a HoA with certain values in it.

I need to have only unique elements from the HoA.

Expected Result:

Key:1
Element:ABC#DEF
Key:2
Element:XYZ#RST
Key:3
Element:LMN

Below is my script:

#!/usr/bin/perl

use strict; use warnings;
use Data::Dumper;

my %Hash = (
            '1' => ['ABC', 'DEF', 'ABC'],
            '2' => ['XYZ', 'RST', 'RST'],
            '3' => ['LMN']
);

print Dumper(\%Hash);

foreach my $key (sort keys %Hash){
    print "Key:$key\n";
    print "Element:", join('#', uniq(@{$Hash{$key}})), "\n";
}

sub uniq { keys { map { $_ => 1 } @_ } };

The script throws me following error:

Experimental keys on scalar is now forbidden at test.pl line 19.
Type of arg 1 to keys must be hash or array (not anonymous hash ({})) at test.pl line 19, near "} }"
Execution of test.pl aborted due to compilation errors.

If I use List::Util's uniq function to get the unique elements with following statement, I am able to get the desired result.

use List::Util qw /uniq/;
...
...
print "-Element_$i=", join('#', uniq @{$Hash{$key}}), "\n";
...

Since I have List::Util's 1.21 Version installed in my environment, which doesn't support uniq functionality as per the List::Util documentation.

How can I get desired result without using List::Util module.

Update/Edit:

I found a solution by adding this line in print statement:

...
print "Element:", join('#', grep { ! $seen{$_} ++ } @{$Hash{$key}}), "\n";
...

Any suggestion would be highly apricated.

vkk05
  • 3,137
  • 11
  • 25

1 Answers1

5

There is a pure Perl implementation of List::Util. If you can't update/install, I think this is one of these times where it's legit to lift out a sub from another module and just copy it into your code.

List::Util::PP's implementation of uniq is as follows:

sub uniq (@) {
  my %seen;
  my $undef;
  my @uniq = grep defined($_) ? !$seen{$_}++ : !$undef++, @_;
  @uniq;
}
simbabque
  • 53,749
  • 8
  • 73
  • 136
  • You could also fatpack this particular PP module with your code though. – simbabque Mar 24 '21 at 09:47
  • I have added the `uniq` sub in the script as well as modified the print statement like this - `print "Element:", join('#', uniq(@{$Hash{$key}})), "\n";`. It gives me the result, but throw's the warning - `main::uniq() called too early to check prototype at test.pl line 15.`. Why so? – vkk05 Mar 24 '21 at 18:22
  • Solved. I have added the `uniq` sub before its being called. – vkk05 Mar 24 '21 at 18:35
  • _You could also fatpack this particular PP.._ Could you please elaborate what does it mean? – vkk05 Mar 24 '21 at 18:36
  • 1
    @vkk05 the prototype is the `(@)`, which lets perl know that there's a list after the sub name, so you can invoke it without parentheses. // Look for App::Fatpack. It's a way of bundling your (pure Perl) dependencies into your script to ship all of it in one file. Similar to webpack or other bundling tools you would see in the JavaScript/Node world. – simbabque Mar 24 '21 at 19:42